rpcrt4/tests: Fix the marshalling test for Win64.
[wine.git] / dlls / wined3d / device.c
blob5378568155950d2b76b53a518adbfa80ed58b1d1
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, UINT Width, UINT Height,
893 WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,
894 DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
895 WINED3DSURFTYPE Impl, IUnknown *parent)
897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
898 IWineD3DSurfaceImpl *object;
899 HRESULT hr;
901 TRACE("(%p) Create surface\n",This);
903 if (Impl == SURFACE_OPENGL && !This->adapter)
905 ERR("OpenGL surfaces are not available without OpenGL.\n");
906 return WINED3DERR_NOTAVAILABLE;
909 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
910 if (!object)
912 ERR("Failed to allocate surface memory.\n");
913 *ppSurface = NULL;
914 return WINED3DERR_OUTOFVIDEOMEMORY;
917 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
918 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent);
919 if (FAILED(hr))
921 WARN("Failed to initialize surface, returning %#x.\n", hr);
922 HeapFree(GetProcessHeap(), 0, object);
923 *ppSurface = NULL;
924 return hr;
927 TRACE("(%p) : Created surface %p\n", This, object);
929 *ppSurface = (IWineD3DSurface *)object;
931 return hr;
934 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
935 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
937 struct wined3d_rendertarget_view *object;
939 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
940 if (!object)
942 ERR("Failed to allocate memory\n");
943 return E_OUTOFMEMORY;
946 object->vtbl = &wined3d_rendertarget_view_vtbl;
947 object->refcount = 1;
948 IWineD3DResource_AddRef(resource);
949 object->resource = resource;
950 object->parent = parent;
952 *rendertarget_view = (IWineD3DRendertargetView *)object;
954 return WINED3D_OK;
957 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
958 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
959 WINED3DPOOL Pool, IWineD3DTexture **ppTexture, IUnknown *parent)
961 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
962 IWineD3DTextureImpl *object;
963 HRESULT hr;
965 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
966 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
967 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
969 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
970 if (!object)
972 ERR("Out of memory\n");
973 *ppTexture = NULL;
974 return WINED3DERR_OUTOFVIDEOMEMORY;
977 object->lpVtbl = &IWineD3DTexture_Vtbl;
979 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent);
980 if (FAILED(hr))
982 WARN("Failed to initialize texture, returning %#x\n", hr);
983 HeapFree(GetProcessHeap(), 0, object);
984 *ppTexture = NULL;
985 return hr;
988 *ppTexture = (IWineD3DTexture *)object;
990 TRACE("(%p) : Created texture %p\n", This, object);
992 return WINED3D_OK;
995 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
996 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
997 WINED3DPOOL Pool, IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent)
999 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1000 IWineD3DVolumeTextureImpl *object;
1001 HRESULT hr;
1003 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1004 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1006 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1007 if (!object)
1009 ERR("Out of memory\n");
1010 *ppVolumeTexture = NULL;
1011 return WINED3DERR_OUTOFVIDEOMEMORY;
1014 object->lpVtbl = &IWineD3DVolumeTexture_Vtbl;
1015 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent);
1016 if (FAILED(hr))
1018 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
1019 HeapFree(GetProcessHeap(), 0, object);
1020 *ppVolumeTexture = NULL;
1021 return hr;
1024 TRACE("(%p) : Created volume texture %p.\n", This, object);
1025 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
1027 return WINED3D_OK;
1030 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1031 UINT Width, UINT Height, UINT Depth, DWORD Usage, WINED3DFORMAT Format,
1032 WINED3DPOOL Pool, IWineD3DVolume **ppVolume, IUnknown *parent)
1034 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1035 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1036 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &GLINFO_LOCATION);
1037 HRESULT hr;
1039 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1040 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1041 return WINED3DERR_INVALIDCALL;
1044 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1045 if (!object)
1047 ERR("Out of memory\n");
1048 *ppVolume = NULL;
1049 return WINED3DERR_OUTOFVIDEOMEMORY;
1052 object->lpVtbl = &IWineD3DVolume_Vtbl;
1053 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_VOLUME, This,
1054 Width * Height * Depth * format_desc->byte_count, Usage, format_desc, Pool, parent);
1055 if (FAILED(hr))
1057 WARN("Failed to initialize resource, returning %#x\n", hr);
1058 HeapFree(GetProcessHeap(), 0, object);
1059 *ppVolume = NULL;
1060 return hr;
1063 TRACE("(%p) : Created resource %p\n", This, object);
1065 *ppVolume = (IWineD3DVolume *)object;
1067 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1068 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1070 object->currentDesc.Width = Width;
1071 object->currentDesc.Height = Height;
1072 object->currentDesc.Depth = Depth;
1074 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1075 object->lockable = TRUE;
1076 object->locked = FALSE;
1077 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1078 object->dirty = TRUE;
1080 volume_add_dirty_box((IWineD3DVolume *)object, NULL);
1082 return WINED3D_OK;
1085 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface,
1086 UINT EdgeLength, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
1087 WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture, IUnknown *parent)
1089 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1090 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1091 HRESULT hr;
1093 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1094 if (!object)
1096 ERR("Out of memory\n");
1097 *ppCubeTexture = NULL;
1098 return WINED3DERR_OUTOFVIDEOMEMORY;
1101 object->lpVtbl = &IWineD3DCubeTexture_Vtbl;
1102 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent);
1103 if (FAILED(hr))
1105 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1106 HeapFree(GetProcessHeap(), 0, object);
1107 *ppCubeTexture = NULL;
1108 return hr;
1111 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1112 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1114 return WINED3D_OK;
1117 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1118 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1119 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1120 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1121 const IWineD3DQueryVtbl *vtable;
1123 /* Just a check to see if we support this type of query */
1124 switch(Type) {
1125 case WINED3DQUERYTYPE_OCCLUSION:
1126 TRACE("(%p) occlusion query\n", This);
1127 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1128 hr = WINED3D_OK;
1129 else
1130 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1132 vtable = &IWineD3DOcclusionQuery_Vtbl;
1133 break;
1135 case WINED3DQUERYTYPE_EVENT:
1136 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1137 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1138 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1140 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1142 vtable = &IWineD3DEventQuery_Vtbl;
1143 hr = WINED3D_OK;
1144 break;
1146 case WINED3DQUERYTYPE_VCACHE:
1147 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1148 case WINED3DQUERYTYPE_VERTEXSTATS:
1149 case WINED3DQUERYTYPE_TIMESTAMP:
1150 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1151 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1152 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1153 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1154 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1155 case WINED3DQUERYTYPE_PIXELTIMINGS:
1156 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1157 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1158 default:
1159 /* Use the base Query vtable until we have a special one for each query */
1160 vtable = &IWineD3DQuery_Vtbl;
1161 FIXME("(%p) Unhandled query type %d\n", This, Type);
1163 if(NULL == ppQuery || hr != WINED3D_OK) {
1164 return hr;
1167 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1168 if(!object)
1170 ERR("Out of memory\n");
1171 *ppQuery = NULL;
1172 return WINED3DERR_OUTOFVIDEOMEMORY;
1175 object->lpVtbl = vtable;
1176 object->type = Type;
1177 object->state = QUERY_CREATED;
1178 object->wineD3DDevice = This;
1179 object->parent = parent;
1180 object->ref = 1;
1182 *ppQuery = (IWineD3DQuery *)object;
1184 /* allocated the 'extended' data based on the type of query requested */
1185 switch(Type){
1186 case WINED3DQUERYTYPE_OCCLUSION:
1187 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1188 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1190 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1191 TRACE("(%p) Allocating data for an occlusion query\n", This);
1193 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1194 ENTER_GL();
1195 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1196 LEAVE_GL();
1197 break;
1199 case WINED3DQUERYTYPE_EVENT:
1200 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1201 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1203 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1204 ENTER_GL();
1205 if(GL_SUPPORT(APPLE_FENCE)) {
1206 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1207 checkGLcall("glGenFencesAPPLE");
1208 } else if(GL_SUPPORT(NV_FENCE)) {
1209 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1210 checkGLcall("glGenFencesNV");
1212 LEAVE_GL();
1213 break;
1215 case WINED3DQUERYTYPE_VCACHE:
1216 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1217 case WINED3DQUERYTYPE_VERTEXSTATS:
1218 case WINED3DQUERYTYPE_TIMESTAMP:
1219 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1220 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1221 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1222 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1223 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1224 case WINED3DQUERYTYPE_PIXELTIMINGS:
1225 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1226 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1227 default:
1228 object->extendedData = 0;
1229 FIXME("(%p) Unhandled query type %d\n",This , Type);
1231 TRACE("(%p) : Created Query %p\n", This, object);
1232 return WINED3D_OK;
1235 /*****************************************************************************
1236 * IWineD3DDeviceImpl_SetupFullscreenWindow
1238 * Helper function that modifies a HWND's Style and ExStyle for proper
1239 * fullscreen use.
1241 * Params:
1242 * iface: Pointer to the IWineD3DDevice interface
1243 * window: Window to setup
1245 *****************************************************************************/
1246 static LONG fullscreen_style(LONG orig_style) {
1247 LONG style = orig_style;
1248 style &= ~WS_CAPTION;
1249 style &= ~WS_THICKFRAME;
1251 /* Make sure the window is managed, otherwise we won't get keyboard input */
1252 style |= WS_POPUP | WS_SYSMENU;
1254 return style;
1257 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1258 LONG exStyle = orig_exStyle;
1260 /* Filter out window decorations */
1261 exStyle &= ~WS_EX_WINDOWEDGE;
1262 exStyle &= ~WS_EX_CLIENTEDGE;
1264 return exStyle;
1267 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1268 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1270 LONG style, exStyle;
1271 /* Don't do anything if an original style is stored.
1272 * That shouldn't happen
1274 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1275 if (This->style || This->exStyle) {
1276 ERR("(%p): Want to change the window parameters of HWND %p, but "
1277 "another style is stored for restoration afterwards\n", This, window);
1280 /* Get the parameters and save them */
1281 style = GetWindowLongW(window, GWL_STYLE);
1282 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1283 This->style = style;
1284 This->exStyle = exStyle;
1286 style = fullscreen_style(style);
1287 exStyle = fullscreen_exStyle(exStyle);
1289 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1290 This->style, This->exStyle, style, exStyle);
1292 SetWindowLongW(window, GWL_STYLE, style);
1293 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1295 /* Inform the window about the update. */
1296 SetWindowPos(window, HWND_TOP, 0, 0,
1297 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1300 /*****************************************************************************
1301 * IWineD3DDeviceImpl_RestoreWindow
1303 * Helper function that restores a windows' properties when taking it out
1304 * of fullscreen mode
1306 * Params:
1307 * iface: Pointer to the IWineD3DDevice interface
1308 * window: Window to setup
1310 *****************************************************************************/
1311 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1312 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1313 LONG style, exStyle;
1315 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1316 * switch, do nothing
1318 if (!This->style && !This->exStyle) return;
1320 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1321 This, window, This->style, This->exStyle);
1323 style = GetWindowLongW(window, GWL_STYLE);
1324 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1326 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1327 * Some applications change it before calling Reset() when switching between windowed and
1328 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1330 if(style == fullscreen_style(This->style) &&
1331 exStyle == fullscreen_style(This->exStyle)) {
1332 SetWindowLongW(window, GWL_STYLE, This->style);
1333 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1336 /* Delete the old values */
1337 This->style = 0;
1338 This->exStyle = 0;
1340 /* Inform the window about the update */
1341 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1342 0, 0, 0, 0, /* Pos, Size, ignored */
1343 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1346 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1347 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1348 WINED3DPRESENT_PARAMETERS *pPresentationParameters, IWineD3DSwapChain **ppSwapChain,
1349 IUnknown *parent, WINED3DSURFTYPE surface_type)
1351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1353 HDC hDc;
1354 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1355 HRESULT hr;
1356 IUnknown *bufferParent;
1357 BOOL displaymode_set = FALSE;
1358 WINED3DDISPLAYMODE Mode;
1359 const struct GlPixelFormatDesc *format_desc;
1361 TRACE("(%p) : Created Additional Swap Chain\n", This);
1363 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1364 * does a device hold a reference to a swap chain giving them a lifetime of the device
1365 * or does the swap chain notify the device of its destruction.
1366 *******************************/
1368 /* Check the params */
1369 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1370 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1371 return WINED3DERR_INVALIDCALL;
1372 } else if (pPresentationParameters->BackBufferCount > 1) {
1373 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");
1376 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1377 if(!object)
1379 ERR("Out of memory\n");
1380 *ppSwapChain = NULL;
1381 return WINED3DERR_OUTOFVIDEOMEMORY;
1384 switch(surface_type) {
1385 case SURFACE_GDI:
1386 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1387 break;
1388 case SURFACE_OPENGL:
1389 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1390 break;
1391 case SURFACE_UNKNOWN:
1392 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1393 HeapFree(GetProcessHeap(), 0, object);
1394 return WINED3DERR_INVALIDCALL;
1396 object->wineD3DDevice = This;
1397 object->parent = parent;
1398 object->ref = 1;
1400 *ppSwapChain = (IWineD3DSwapChain *)object;
1402 /*********************
1403 * Lookup the window Handle and the relating X window handle
1404 ********************/
1406 /* Setup hwnd we are using, plus which display this equates to */
1407 object->win_handle = pPresentationParameters->hDeviceWindow;
1408 if (!object->win_handle) {
1409 object->win_handle = This->createParms.hFocusWindow;
1411 if(!pPresentationParameters->Windowed && object->win_handle) {
1412 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1413 pPresentationParameters->BackBufferWidth,
1414 pPresentationParameters->BackBufferHeight);
1417 hDc = GetDC(object->win_handle);
1418 TRACE("Using hDc %p\n", hDc);
1420 if (NULL == hDc) {
1421 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1422 return WINED3DERR_NOTAVAILABLE;
1425 /* Get info on the current display setup */
1426 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1427 object->orig_width = Mode.Width;
1428 object->orig_height = Mode.Height;
1429 object->orig_fmt = Mode.Format;
1430 format_desc = getFormatDescEntry(Mode.Format, &GLINFO_LOCATION);
1432 if (pPresentationParameters->Windowed &&
1433 ((pPresentationParameters->BackBufferWidth == 0) ||
1434 (pPresentationParameters->BackBufferHeight == 0) ||
1435 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1437 RECT Rect;
1438 GetClientRect(object->win_handle, &Rect);
1440 if (pPresentationParameters->BackBufferWidth == 0) {
1441 pPresentationParameters->BackBufferWidth = Rect.right;
1442 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1444 if (pPresentationParameters->BackBufferHeight == 0) {
1445 pPresentationParameters->BackBufferHeight = Rect.bottom;
1446 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1448 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1449 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1450 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1454 /* Put the correct figures in the presentation parameters */
1455 TRACE("Copying across presentation parameters\n");
1456 object->presentParms = *pPresentationParameters;
1458 TRACE("calling rendertarget CB\n");
1459 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1460 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1461 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1462 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->frontBuffer);
1463 if (SUCCEEDED(hr)) {
1464 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1465 ((IWineD3DSurfaceImpl *)object->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
1466 if(surface_type == SURFACE_OPENGL) {
1467 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1469 } else {
1470 ERR("Failed to create the front buffer\n");
1471 goto error;
1474 /*********************
1475 * Windowed / Fullscreen
1476 *******************/
1479 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1480 * so we should really check to see if there is a fullscreen swapchain already
1481 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1482 **************************************/
1484 if (!pPresentationParameters->Windowed) {
1485 WINED3DDISPLAYMODE mode;
1488 /* Change the display settings */
1489 mode.Width = pPresentationParameters->BackBufferWidth;
1490 mode.Height = pPresentationParameters->BackBufferHeight;
1491 mode.Format = pPresentationParameters->BackBufferFormat;
1492 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1494 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1495 displaymode_set = TRUE;
1499 * Create an opengl context for the display visual
1500 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1501 * use different properties after that point in time. FIXME: How to handle when requested format
1502 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1503 * it chooses is identical to the one already being used!
1504 **********************************/
1505 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1507 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1508 if(!object->context) {
1509 ERR("Failed to create the context array\n");
1510 hr = E_OUTOFMEMORY;
1511 goto error;
1513 object->num_contexts = 1;
1515 if(surface_type == SURFACE_OPENGL) {
1516 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1517 if (!object->context[0]) {
1518 ERR("Failed to create a new context\n");
1519 hr = WINED3DERR_NOTAVAILABLE;
1520 goto error;
1521 } else {
1522 TRACE("Context created (HWND=%p, glContext=%p)\n",
1523 object->win_handle, object->context[0]->glCtx);
1527 /*********************
1528 * Create the back, front and stencil buffers
1529 *******************/
1530 if(object->presentParms.BackBufferCount > 0) {
1531 UINT i;
1533 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1534 if(!object->backBuffer) {
1535 ERR("Out of memory\n");
1536 hr = E_OUTOFMEMORY;
1537 goto error;
1540 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1541 TRACE("calling rendertarget CB\n");
1542 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1543 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1544 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1545 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->backBuffer[i]);
1546 if(SUCCEEDED(hr)) {
1547 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1548 ((IWineD3DSurfaceImpl *)object->backBuffer[i])->Flags |= SFLAG_SWAPCHAIN;
1549 } else {
1550 ERR("Cannot create new back buffer\n");
1551 goto error;
1553 if(surface_type == SURFACE_OPENGL) {
1554 ENTER_GL();
1555 glDrawBuffer(GL_BACK);
1556 checkGLcall("glDrawBuffer(GL_BACK)");
1557 LEAVE_GL();
1560 } else {
1561 object->backBuffer = NULL;
1563 /* Single buffering - draw to front buffer */
1564 if(surface_type == SURFACE_OPENGL) {
1565 ENTER_GL();
1566 glDrawBuffer(GL_FRONT);
1567 checkGLcall("glDrawBuffer(GL_FRONT)");
1568 LEAVE_GL();
1572 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1573 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1574 TRACE("Creating depth stencil buffer\n");
1575 if (This->auto_depth_stencil_buffer == NULL ) {
1576 hr = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent, parent,
1577 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1578 object->presentParms.AutoDepthStencilFormat, object->presentParms.MultiSampleType,
1579 object->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */,
1580 &This->auto_depth_stencil_buffer);
1581 if (SUCCEEDED(hr)) {
1582 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1583 } else {
1584 ERR("Failed to create the auto depth stencil\n");
1585 goto error;
1590 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1592 TRACE("Created swapchain %p\n", object);
1593 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1594 return WINED3D_OK;
1596 error:
1597 if (displaymode_set) {
1598 DEVMODEW devmode;
1599 RECT clip_rc;
1601 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1602 ClipCursor(NULL);
1604 /* Change the display settings */
1605 memset(&devmode, 0, sizeof(devmode));
1606 devmode.dmSize = sizeof(devmode);
1607 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1608 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1609 devmode.dmPelsWidth = object->orig_width;
1610 devmode.dmPelsHeight = object->orig_height;
1611 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1614 if (object->backBuffer) {
1615 UINT i;
1616 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1617 if(object->backBuffer[i]) {
1618 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1619 IUnknown_Release(bufferParent); /* once for the get parent */
1620 if (IUnknown_Release(bufferParent) > 0) {
1621 FIXME("(%p) Something's still holding the back buffer\n",This);
1625 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1626 object->backBuffer = NULL;
1628 if(object->context && object->context[0])
1629 DestroyContext(This, object->context[0]);
1630 if(object->frontBuffer) {
1631 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1632 IUnknown_Release(bufferParent); /* once for the get parent */
1633 if (IUnknown_Release(bufferParent) > 0) {
1634 FIXME("(%p) Something's still holding the front buffer\n",This);
1637 HeapFree(GetProcessHeap(), 0, object);
1638 return hr;
1641 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1642 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1643 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1644 TRACE("(%p)\n", This);
1646 return This->NumberOfSwapChains;
1649 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1650 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1651 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1653 if(iSwapChain < This->NumberOfSwapChains) {
1654 *pSwapChain = This->swapchains[iSwapChain];
1655 IWineD3DSwapChain_AddRef(*pSwapChain);
1656 TRACE("(%p) returning %p\n", This, *pSwapChain);
1657 return WINED3D_OK;
1658 } else {
1659 TRACE("Swapchain out of range\n");
1660 *pSwapChain = NULL;
1661 return WINED3DERR_INVALIDCALL;
1665 /*****
1666 * Vertex Declaration
1667 *****/
1668 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1669 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1670 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1671 IWineD3DVertexDeclarationImpl *object = NULL;
1672 HRESULT hr = WINED3D_OK;
1674 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1675 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1677 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1678 if(!object)
1680 ERR("Out of memory\n");
1681 *ppVertexDeclaration = NULL;
1682 return WINED3DERR_OUTOFVIDEOMEMORY;
1685 object->lpVtbl = &IWineD3DVertexDeclaration_Vtbl;
1686 object->wineD3DDevice = This;
1687 object->parent = parent;
1688 object->ref = 1;
1690 *ppVertexDeclaration = (IWineD3DVertexDeclaration *)object;
1692 hr = vertexdeclaration_init(object, elements, element_count);
1694 if(FAILED(hr)) {
1695 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
1696 *ppVertexDeclaration = NULL;
1699 return hr;
1702 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1703 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1705 unsigned int idx, idx2;
1706 unsigned int offset;
1707 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1708 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1709 BOOL has_blend_idx = has_blend &&
1710 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1711 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1712 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1713 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1714 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1715 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1716 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1718 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1719 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1720 WINED3DVERTEXELEMENT *elements = NULL;
1722 unsigned int size;
1723 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1724 if (has_blend_idx) num_blends--;
1726 /* Compute declaration size */
1727 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1728 has_psize + has_diffuse + has_specular + num_textures;
1730 /* convert the declaration */
1731 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1732 if (!elements) return ~0U;
1734 idx = 0;
1735 if (has_pos) {
1736 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1737 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1738 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
1740 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1741 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1742 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1744 else {
1745 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1746 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1748 elements[idx].usage_idx = 0;
1749 idx++;
1751 if (has_blend && (num_blends > 0)) {
1752 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1753 elements[idx].format = WINED3DFMT_A8R8G8B8;
1754 else {
1755 switch(num_blends) {
1756 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
1757 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
1758 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
1759 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
1760 default:
1761 ERR("Unexpected amount of blend values: %u\n", num_blends);
1764 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1765 elements[idx].usage_idx = 0;
1766 idx++;
1768 if (has_blend_idx) {
1769 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1770 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1771 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
1772 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1773 elements[idx].format = WINED3DFMT_A8R8G8B8;
1774 else
1775 elements[idx].format = WINED3DFMT_R32_FLOAT;
1776 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
1777 elements[idx].usage_idx = 0;
1778 idx++;
1780 if (has_normal) {
1781 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1782 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
1783 elements[idx].usage_idx = 0;
1784 idx++;
1786 if (has_psize) {
1787 elements[idx].format = WINED3DFMT_R32_FLOAT;
1788 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
1789 elements[idx].usage_idx = 0;
1790 idx++;
1792 if (has_diffuse) {
1793 elements[idx].format = WINED3DFMT_A8R8G8B8;
1794 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1795 elements[idx].usage_idx = 0;
1796 idx++;
1798 if (has_specular) {
1799 elements[idx].format = WINED3DFMT_A8R8G8B8;
1800 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1801 elements[idx].usage_idx = 1;
1802 idx++;
1804 for (idx2 = 0; idx2 < num_textures; idx2++) {
1805 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1806 switch (numcoords) {
1807 case WINED3DFVF_TEXTUREFORMAT1:
1808 elements[idx].format = WINED3DFMT_R32_FLOAT;
1809 break;
1810 case WINED3DFVF_TEXTUREFORMAT2:
1811 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
1812 break;
1813 case WINED3DFVF_TEXTUREFORMAT3:
1814 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1815 break;
1816 case WINED3DFVF_TEXTUREFORMAT4:
1817 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1818 break;
1820 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
1821 elements[idx].usage_idx = idx2;
1822 idx++;
1825 /* Now compute offsets, and initialize the rest of the fields */
1826 for (idx = 0, offset = 0; idx < size; ++idx)
1828 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
1829 elements[idx].input_slot = 0;
1830 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1831 elements[idx].offset = offset;
1832 offset += format_desc->component_count * format_desc->component_size;
1835 *ppVertexElements = elements;
1836 return size;
1839 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1840 WINED3DVERTEXELEMENT* elements = NULL;
1841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1842 unsigned int size;
1843 DWORD hr;
1845 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1846 if (size == ~0U) return WINED3DERR_OUTOFVIDEOMEMORY;
1848 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1849 HeapFree(GetProcessHeap(), 0, elements);
1850 if (hr != S_OK) return hr;
1852 return WINED3D_OK;
1855 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1856 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1857 IWineD3DVertexShader **ppVertexShader, IUnknown *parent)
1859 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1860 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1861 HRESULT hr = WINED3D_OK;
1863 if (!pFunction) return WINED3DERR_INVALIDCALL;
1865 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1866 if (!object)
1868 ERR("Out of memory\n");
1869 *ppVertexShader = NULL;
1870 return WINED3DERR_OUTOFVIDEOMEMORY;
1873 object->lpVtbl = &IWineD3DVertexShader_Vtbl;
1874 object->parent = parent;
1875 shader_init(&object->baseShader, iface);
1876 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1877 *ppVertexShader = (IWineD3DVertexShader *)object;
1879 TRACE("(%p) : Created vertex shader %p\n", This, *ppVertexShader);
1881 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction, output_signature);
1882 if (FAILED(hr))
1884 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
1885 IWineD3DVertexShader_Release(*ppVertexShader);
1886 *ppVertexShader = NULL;
1887 return hr;
1890 return hr;
1893 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1894 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1895 IWineD3DPixelShader **ppPixelShader, IUnknown *parent)
1897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1898 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1899 HRESULT hr = WINED3D_OK;
1901 if (!pFunction) return WINED3DERR_INVALIDCALL;
1903 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1904 if (!object)
1906 ERR("Out of memory\n");
1907 *ppPixelShader = NULL;
1908 return WINED3DERR_OUTOFVIDEOMEMORY;
1911 object->lpVtbl = &IWineD3DPixelShader_Vtbl;
1912 object->parent = parent;
1913 shader_init(&object->baseShader, iface);
1914 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1915 *ppPixelShader = (IWineD3DPixelShader *)object;
1917 TRACE("(%p) : Created pixel shader %p\n", This, *ppPixelShader);
1919 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction, output_signature);
1920 if (FAILED(hr))
1922 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
1923 IWineD3DPixelShader_Release(*ppPixelShader);
1924 *ppPixelShader = NULL;
1925 return hr;
1928 return hr;
1931 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1932 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1934 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1935 IWineD3DPaletteImpl *object;
1936 HRESULT hr;
1937 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1939 /* Create the new object */
1940 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1941 if(!object) {
1942 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1943 return E_OUTOFMEMORY;
1946 object->lpVtbl = &IWineD3DPalette_Vtbl;
1947 object->ref = 1;
1948 object->Flags = Flags;
1949 object->parent = Parent;
1950 object->wineD3DDevice = This;
1951 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1952 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1954 if(!object->hpal) {
1955 HeapFree( GetProcessHeap(), 0, object);
1956 return E_OUTOFMEMORY;
1959 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1960 if(FAILED(hr)) {
1961 IWineD3DPalette_Release((IWineD3DPalette *) object);
1962 return hr;
1965 *Palette = (IWineD3DPalette *) object;
1967 return WINED3D_OK;
1970 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1971 HBITMAP hbm;
1972 BITMAP bm;
1973 HRESULT hr;
1974 HDC dcb = NULL, dcs = NULL;
1975 WINEDDCOLORKEY colorkey;
1977 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1978 if(hbm)
1980 GetObjectA(hbm, sizeof(BITMAP), &bm);
1981 dcb = CreateCompatibleDC(NULL);
1982 if(!dcb) goto out;
1983 SelectObject(dcb, hbm);
1985 else
1987 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1988 * couldn't be loaded
1990 memset(&bm, 0, sizeof(bm));
1991 bm.bmWidth = 32;
1992 bm.bmHeight = 32;
1995 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5, TRUE,
1996 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL, NULL);
1997 if(FAILED(hr)) {
1998 ERR("Wine logo requested, but failed to create surface\n");
1999 goto out;
2002 if(dcb) {
2003 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
2004 if(FAILED(hr)) goto out;
2005 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
2006 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
2008 colorkey.dwColorSpaceLowValue = 0;
2009 colorkey.dwColorSpaceHighValue = 0;
2010 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2011 } else {
2012 /* Fill the surface with a white color to show that wined3d is there */
2013 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2016 out:
2017 if(dcb) {
2018 DeleteDC(dcb);
2020 if(hbm) {
2021 DeleteObject(hbm);
2023 return;
2026 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2027 unsigned int i;
2028 /* Under DirectX you can have texture stage operations even if no texture is
2029 bound, whereas opengl will only do texture operations when a valid texture is
2030 bound. We emulate this by creating dummy textures and binding them to each
2031 texture stage, but disable all stages by default. Hence if a stage is enabled
2032 then the default texture will kick in until replaced by a SetTexture call */
2033 ENTER_GL();
2035 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2036 /* The dummy texture does not have client storage backing */
2037 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2038 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2040 for (i = 0; i < GL_LIMITS(textures); i++) {
2041 GLubyte white = 255;
2043 /* Make appropriate texture active */
2044 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2045 checkGLcall("glActiveTextureARB");
2047 /* Generate an opengl texture name */
2048 glGenTextures(1, &This->dummyTextureName[i]);
2049 checkGLcall("glGenTextures");
2050 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2052 /* Generate a dummy 2d texture (not using 1d because they cause many
2053 * DRI drivers fall back to sw) */
2054 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2055 checkGLcall("glBindTexture");
2057 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2058 checkGLcall("glTexImage2D");
2060 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2061 /* Reenable because if supported it is enabled by default */
2062 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2063 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2066 LEAVE_GL();
2069 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
2070 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2072 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2073 IWineD3DSwapChainImpl *swapchain = NULL;
2074 HRESULT hr;
2075 DWORD state;
2076 unsigned int i;
2078 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
2080 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2081 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2083 /* TODO: Test if OpenGL is compiled in and loaded */
2085 TRACE("(%p) : Creating stateblock\n", This);
2086 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2087 hr = IWineD3DDevice_CreateStateBlock(iface,
2088 WINED3DSBT_INIT,
2089 (IWineD3DStateBlock **)&This->stateBlock,
2090 NULL);
2091 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2092 WARN("Failed to create stateblock\n");
2093 goto err_out;
2095 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2096 This->updateStateBlock = This->stateBlock;
2097 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2099 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2100 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2102 This->NumberOfPalettes = 1;
2103 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2104 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2105 ERR("Out of memory!\n");
2106 goto err_out;
2108 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2109 if(!This->palettes[0]) {
2110 ERR("Out of memory!\n");
2111 goto err_out;
2113 for (i = 0; i < 256; ++i) {
2114 This->palettes[0][i].peRed = 0xFF;
2115 This->palettes[0][i].peGreen = 0xFF;
2116 This->palettes[0][i].peBlue = 0xFF;
2117 This->palettes[0][i].peFlags = 0xFF;
2119 This->currentPalette = 0;
2121 /* Initialize the texture unit mapping to a 1:1 mapping */
2122 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2123 if (state < GL_LIMITS(fragment_samplers)) {
2124 This->texUnitMap[state] = state;
2125 This->rev_tex_unit_map[state] = state;
2126 } else {
2127 This->texUnitMap[state] = -1;
2128 This->rev_tex_unit_map[state] = -1;
2132 /* Setup the implicit swapchain */
2133 TRACE("Creating implicit swapchain\n");
2134 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2135 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2136 if (FAILED(hr))
2138 WARN("Failed to create implicit swapchain\n");
2139 goto err_out;
2142 This->NumberOfSwapChains = 1;
2143 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2144 if(!This->swapchains) {
2145 ERR("Out of memory!\n");
2146 goto err_out;
2148 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2150 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2151 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2152 This->render_targets[0] = swapchain->backBuffer[0];
2153 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2155 else {
2156 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2157 This->render_targets[0] = swapchain->frontBuffer;
2158 This->lastActiveRenderTarget = swapchain->frontBuffer;
2160 IWineD3DSurface_AddRef(This->render_targets[0]);
2161 This->activeContext = swapchain->context[0];
2162 This->lastThread = GetCurrentThreadId();
2164 /* Depth Stencil support */
2165 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2166 if (NULL != This->stencilBufferTarget) {
2167 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2170 hr = This->shader_backend->shader_alloc_private(iface);
2171 if(FAILED(hr)) {
2172 TRACE("Shader private data couldn't be allocated\n");
2173 goto err_out;
2175 hr = This->frag_pipe->alloc_private(iface);
2176 if(FAILED(hr)) {
2177 TRACE("Fragment pipeline private data couldn't be allocated\n");
2178 goto err_out;
2180 hr = This->blitter->alloc_private(iface);
2181 if(FAILED(hr)) {
2182 TRACE("Blitter private data couldn't be allocated\n");
2183 goto err_out;
2186 /* Set up some starting GL setup */
2188 /* Setup all the devices defaults */
2189 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2190 create_dummy_textures(This);
2192 ENTER_GL();
2194 /* Initialize the current view state */
2195 This->view_ident = 1;
2196 This->contexts[0]->last_was_rhw = 0;
2197 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2198 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2200 switch(wined3d_settings.offscreen_rendering_mode) {
2201 case ORM_FBO:
2202 case ORM_PBUFFER:
2203 This->offscreenBuffer = GL_BACK;
2204 break;
2206 case ORM_BACKBUFFER:
2208 if(This->activeContext->aux_buffers > 0) {
2209 TRACE("Using auxilliary buffer for offscreen rendering\n");
2210 This->offscreenBuffer = GL_AUX0;
2211 } else {
2212 TRACE("Using back buffer for offscreen rendering\n");
2213 This->offscreenBuffer = GL_BACK;
2218 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2219 LEAVE_GL();
2221 /* Clear the screen */
2222 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2223 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2224 0x00, 1.0, 0);
2226 This->d3d_initialized = TRUE;
2228 if(wined3d_settings.logo) {
2229 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2231 This->highest_dirty_ps_const = 0;
2232 This->highest_dirty_vs_const = 0;
2233 return WINED3D_OK;
2235 err_out:
2236 HeapFree(GetProcessHeap(), 0, This->render_targets);
2237 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2238 HeapFree(GetProcessHeap(), 0, This->swapchains);
2239 This->NumberOfSwapChains = 0;
2240 if(This->palettes) {
2241 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2242 HeapFree(GetProcessHeap(), 0, This->palettes);
2244 This->NumberOfPalettes = 0;
2245 if(swapchain) {
2246 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2248 if(This->stateBlock) {
2249 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2250 This->stateBlock = NULL;
2252 if (This->blit_priv) {
2253 This->blitter->free_private(iface);
2255 if (This->fragment_priv) {
2256 This->frag_pipe->free_private(iface);
2258 if (This->shader_priv) {
2259 This->shader_backend->shader_free_private(iface);
2261 return hr;
2264 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2265 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2267 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2268 IWineD3DSwapChainImpl *swapchain = NULL;
2269 HRESULT hr;
2271 /* Setup the implicit swapchain */
2272 TRACE("Creating implicit swapchain\n");
2273 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2274 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2275 if (FAILED(hr))
2277 WARN("Failed to create implicit swapchain\n");
2278 goto err_out;
2281 This->NumberOfSwapChains = 1;
2282 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2283 if(!This->swapchains) {
2284 ERR("Out of memory!\n");
2285 goto err_out;
2287 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2288 return WINED3D_OK;
2290 err_out:
2291 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2292 return hr;
2295 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2297 IWineD3DResource_UnLoad(resource);
2298 IWineD3DResource_Release(resource);
2299 return WINED3D_OK;
2302 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2304 int sampler;
2305 UINT i;
2306 TRACE("(%p)\n", This);
2308 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2310 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2311 * it was created. Thus make sure a context is active for the glDelete* calls
2313 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2315 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2317 /* Unload resources */
2318 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2320 TRACE("Deleting high order patches\n");
2321 for(i = 0; i < PATCHMAP_SIZE; i++) {
2322 struct list *e1, *e2;
2323 struct WineD3DRectPatch *patch;
2324 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2325 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2326 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2330 /* Delete the palette conversion shader if it is around */
2331 if(This->paletteConversionShader) {
2332 ENTER_GL();
2333 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2334 LEAVE_GL();
2335 This->paletteConversionShader = 0;
2338 /* Delete the pbuffer context if there is any */
2339 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2341 /* Delete the mouse cursor texture */
2342 if(This->cursorTexture) {
2343 ENTER_GL();
2344 glDeleteTextures(1, &This->cursorTexture);
2345 LEAVE_GL();
2346 This->cursorTexture = 0;
2349 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2350 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2352 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2353 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2356 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2357 * private data, it might contain opengl pointers
2359 if(This->depth_blt_texture) {
2360 ENTER_GL();
2361 glDeleteTextures(1, &This->depth_blt_texture);
2362 LEAVE_GL();
2363 This->depth_blt_texture = 0;
2365 if (This->depth_blt_rb) {
2366 ENTER_GL();
2367 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2368 LEAVE_GL();
2369 This->depth_blt_rb = 0;
2370 This->depth_blt_rb_w = 0;
2371 This->depth_blt_rb_h = 0;
2374 /* Release the update stateblock */
2375 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2376 if(This->updateStateBlock != This->stateBlock)
2377 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2379 This->updateStateBlock = NULL;
2381 { /* because were not doing proper internal refcounts releasing the primary state block
2382 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2383 to set this->stateBlock = NULL; first */
2384 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2385 This->stateBlock = NULL;
2387 /* Release the stateblock */
2388 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2389 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2393 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2394 This->blitter->free_private(iface);
2395 This->frag_pipe->free_private(iface);
2396 This->shader_backend->shader_free_private(iface);
2398 /* Release the buffers (with sanity checks)*/
2399 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2400 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2401 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2402 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2404 This->stencilBufferTarget = NULL;
2406 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2407 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2408 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2410 TRACE("Setting rendertarget to NULL\n");
2411 This->render_targets[0] = NULL;
2413 if (This->auto_depth_stencil_buffer) {
2414 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2415 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2417 This->auto_depth_stencil_buffer = NULL;
2420 for(i=0; i < This->NumberOfSwapChains; i++) {
2421 TRACE("Releasing the implicit swapchain %d\n", i);
2422 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2423 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2427 HeapFree(GetProcessHeap(), 0, This->swapchains);
2428 This->swapchains = NULL;
2429 This->NumberOfSwapChains = 0;
2431 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2432 HeapFree(GetProcessHeap(), 0, This->palettes);
2433 This->palettes = NULL;
2434 This->NumberOfPalettes = 0;
2436 HeapFree(GetProcessHeap(), 0, This->render_targets);
2437 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2438 This->render_targets = NULL;
2439 This->draw_buffers = NULL;
2441 This->d3d_initialized = FALSE;
2442 return WINED3D_OK;
2445 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2446 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2447 unsigned int i;
2449 for(i=0; i < This->NumberOfSwapChains; i++) {
2450 TRACE("Releasing the implicit swapchain %d\n", i);
2451 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2452 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2456 HeapFree(GetProcessHeap(), 0, This->swapchains);
2457 This->swapchains = NULL;
2458 This->NumberOfSwapChains = 0;
2459 return WINED3D_OK;
2462 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2463 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2464 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2466 * There is no way to deactivate thread safety once it is enabled.
2468 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2469 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2471 /*For now just store the flag(needed in case of ddraw) */
2472 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2474 return;
2477 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2478 const WINED3DDISPLAYMODE* pMode) {
2479 DEVMODEW devmode;
2480 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2481 LONG ret;
2482 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &GLINFO_LOCATION);
2483 RECT clip_rc;
2485 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2487 /* Resize the screen even without a window:
2488 * The app could have unset it with SetCooperativeLevel, but not called
2489 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2490 * but we don't have any hwnd
2493 memset(&devmode, 0, sizeof(devmode));
2494 devmode.dmSize = sizeof(devmode);
2495 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2496 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2497 devmode.dmPelsWidth = pMode->Width;
2498 devmode.dmPelsHeight = pMode->Height;
2500 devmode.dmDisplayFrequency = pMode->RefreshRate;
2501 if (pMode->RefreshRate != 0) {
2502 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2505 /* Only change the mode if necessary */
2506 if( (This->ddraw_width == pMode->Width) &&
2507 (This->ddraw_height == pMode->Height) &&
2508 (This->ddraw_format == pMode->Format) &&
2509 (pMode->RefreshRate == 0) ) {
2510 return WINED3D_OK;
2513 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2514 if (ret != DISP_CHANGE_SUCCESSFUL) {
2515 if(devmode.dmDisplayFrequency != 0) {
2516 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2517 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2518 devmode.dmDisplayFrequency = 0;
2519 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2521 if(ret != DISP_CHANGE_SUCCESSFUL) {
2522 return WINED3DERR_NOTAVAILABLE;
2526 /* Store the new values */
2527 This->ddraw_width = pMode->Width;
2528 This->ddraw_height = pMode->Height;
2529 This->ddraw_format = pMode->Format;
2531 /* And finally clip mouse to our screen */
2532 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2533 ClipCursor(&clip_rc);
2535 return WINED3D_OK;
2538 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2540 *ppD3D= This->wineD3D;
2541 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2542 IWineD3D_AddRef(*ppD3D);
2543 return WINED3D_OK;
2546 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2547 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2549 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2550 (This->adapter->TextureRam/(1024*1024)),
2551 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2552 /* return simulated texture memory left */
2553 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2556 /*****
2557 * Get / Set Stream Source
2558 *****/
2559 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2560 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2562 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2563 IWineD3DBuffer *oldSrc;
2565 if (StreamNumber >= MAX_STREAMS) {
2566 WARN("Stream out of range %d\n", StreamNumber);
2567 return WINED3DERR_INVALIDCALL;
2568 } else if(OffsetInBytes & 0x3) {
2569 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2570 return WINED3DERR_INVALIDCALL;
2573 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2574 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2576 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2578 if(oldSrc == pStreamData &&
2579 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2580 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2581 TRACE("Application is setting the old values over, nothing to do\n");
2582 return WINED3D_OK;
2585 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2586 if (pStreamData) {
2587 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2588 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2591 /* Handle recording of state blocks */
2592 if (This->isRecordingState) {
2593 TRACE("Recording... not performing anything\n");
2594 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2595 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2596 return WINED3D_OK;
2599 if (pStreamData != NULL) {
2600 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2601 IWineD3DBuffer_AddRef(pStreamData);
2603 if (oldSrc != NULL) {
2604 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2605 IWineD3DBuffer_Release(oldSrc);
2608 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2610 return WINED3D_OK;
2613 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2614 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2616 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2618 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2619 This->stateBlock->streamSource[StreamNumber],
2620 This->stateBlock->streamOffset[StreamNumber],
2621 This->stateBlock->streamStride[StreamNumber]);
2623 if (StreamNumber >= MAX_STREAMS) {
2624 WARN("Stream out of range %d\n", StreamNumber);
2625 return WINED3DERR_INVALIDCALL;
2627 *pStream = This->stateBlock->streamSource[StreamNumber];
2628 *pStride = This->stateBlock->streamStride[StreamNumber];
2629 if (pOffset) {
2630 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2633 if (*pStream != NULL) {
2634 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2636 return WINED3D_OK;
2639 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2640 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2641 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2642 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2644 /* Verify input at least in d3d9 this is invalid*/
2645 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2646 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2647 return WINED3DERR_INVALIDCALL;
2649 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2650 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2651 return WINED3DERR_INVALIDCALL;
2653 if( Divider == 0 ){
2654 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2655 return WINED3DERR_INVALIDCALL;
2658 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2659 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2661 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2662 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2664 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2665 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2666 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2669 return WINED3D_OK;
2672 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2673 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2675 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2676 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2678 TRACE("(%p) : returning %d\n", This, *Divider);
2680 return WINED3D_OK;
2683 /*****
2684 * Get / Set & Multiply Transform
2685 *****/
2686 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2687 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2689 /* Most of this routine, comments included copied from ddraw tree initially: */
2690 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2692 /* Handle recording of state blocks */
2693 if (This->isRecordingState) {
2694 TRACE("Recording... not performing anything\n");
2695 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2696 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2697 return WINED3D_OK;
2701 * If the new matrix is the same as the current one,
2702 * we cut off any further processing. this seems to be a reasonable
2703 * optimization because as was noticed, some apps (warcraft3 for example)
2704 * tend towards setting the same matrix repeatedly for some reason.
2706 * From here on we assume that the new matrix is different, wherever it matters.
2708 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2709 TRACE("The app is setting the same matrix over again\n");
2710 return WINED3D_OK;
2711 } else {
2712 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2716 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2717 where ViewMat = Camera space, WorldMat = world space.
2719 In OpenGL, camera and world space is combined into GL_MODELVIEW
2720 matrix. The Projection matrix stay projection matrix.
2723 /* Capture the times we can just ignore the change for now */
2724 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2725 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2726 /* Handled by the state manager */
2729 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2730 return WINED3D_OK;
2733 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2734 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2735 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2736 *pMatrix = This->stateBlock->transforms[State];
2737 return WINED3D_OK;
2740 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2741 const WINED3DMATRIX *mat = NULL;
2742 WINED3DMATRIX temp;
2744 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2745 * below means it will be recorded in a state block change, but it
2746 * works regardless where it is recorded.
2747 * If this is found to be wrong, change to StateBlock.
2749 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2750 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2752 if (State <= HIGHEST_TRANSFORMSTATE)
2754 mat = &This->updateStateBlock->transforms[State];
2755 } else {
2756 FIXME("Unhandled transform state!!\n");
2759 multiply_matrix(&temp, mat, pMatrix);
2761 /* Apply change via set transform - will reapply to eg. lights this way */
2762 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2765 /*****
2766 * Get / Set Light
2767 *****/
2768 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2769 you can reference any indexes you want as long as that number max are enabled at any
2770 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2771 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2772 but when recording, just build a chain pretty much of commands to be replayed. */
2774 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2775 float rho;
2776 PLIGHTINFOEL *object = NULL;
2777 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2778 struct list *e;
2780 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2781 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2783 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2784 * the gl driver.
2786 if(!pLight) {
2787 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2788 return WINED3DERR_INVALIDCALL;
2791 switch(pLight->Type) {
2792 case WINED3DLIGHT_POINT:
2793 case WINED3DLIGHT_SPOT:
2794 case WINED3DLIGHT_PARALLELPOINT:
2795 case WINED3DLIGHT_GLSPOT:
2796 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2797 * most wanted
2799 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2800 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2801 return WINED3DERR_INVALIDCALL;
2803 break;
2805 case WINED3DLIGHT_DIRECTIONAL:
2806 /* Ignores attenuation */
2807 break;
2809 default:
2810 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2811 return WINED3DERR_INVALIDCALL;
2814 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2815 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2816 if(object->OriginalIndex == Index) break;
2817 object = NULL;
2820 if(!object) {
2821 TRACE("Adding new light\n");
2822 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2823 if(!object) {
2824 ERR("Out of memory error when allocating a light\n");
2825 return E_OUTOFMEMORY;
2827 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2828 object->glIndex = -1;
2829 object->OriginalIndex = Index;
2830 object->changed = TRUE;
2833 /* Initialize the object */
2834 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,
2835 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2836 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2837 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2838 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2839 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2840 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2842 /* Save away the information */
2843 object->OriginalParms = *pLight;
2845 switch (pLight->Type) {
2846 case WINED3DLIGHT_POINT:
2847 /* Position */
2848 object->lightPosn[0] = pLight->Position.x;
2849 object->lightPosn[1] = pLight->Position.y;
2850 object->lightPosn[2] = pLight->Position.z;
2851 object->lightPosn[3] = 1.0f;
2852 object->cutoff = 180.0f;
2853 /* FIXME: Range */
2854 break;
2856 case WINED3DLIGHT_DIRECTIONAL:
2857 /* Direction */
2858 object->lightPosn[0] = -pLight->Direction.x;
2859 object->lightPosn[1] = -pLight->Direction.y;
2860 object->lightPosn[2] = -pLight->Direction.z;
2861 object->lightPosn[3] = 0.0;
2862 object->exponent = 0.0f;
2863 object->cutoff = 180.0f;
2864 break;
2866 case WINED3DLIGHT_SPOT:
2867 /* Position */
2868 object->lightPosn[0] = pLight->Position.x;
2869 object->lightPosn[1] = pLight->Position.y;
2870 object->lightPosn[2] = pLight->Position.z;
2871 object->lightPosn[3] = 1.0;
2873 /* Direction */
2874 object->lightDirn[0] = pLight->Direction.x;
2875 object->lightDirn[1] = pLight->Direction.y;
2876 object->lightDirn[2] = pLight->Direction.z;
2877 object->lightDirn[3] = 1.0;
2880 * opengl-ish and d3d-ish spot lights use too different models for the
2881 * light "intensity" as a function of the angle towards the main light direction,
2882 * so we only can approximate very roughly.
2883 * however spot lights are rather rarely used in games (if ever used at all).
2884 * furthermore if still used, probably nobody pays attention to such details.
2886 if (pLight->Falloff == 0) {
2887 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2888 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2889 * will always be 1.0 for both of them, and we don't have to care for the
2890 * rest of the rather complex calculation
2892 object->exponent = 0;
2893 } else {
2894 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2895 if (rho < 0.0001) rho = 0.0001f;
2896 object->exponent = -0.3/log(cos(rho/2));
2898 if (object->exponent > 128.0) {
2899 object->exponent = 128.0;
2901 object->cutoff = pLight->Phi*90/M_PI;
2903 /* FIXME: Range */
2904 break;
2906 default:
2907 FIXME("Unrecognized light type %d\n", pLight->Type);
2910 /* Update the live definitions if the light is currently assigned a glIndex */
2911 if (object->glIndex != -1 && !This->isRecordingState) {
2912 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2914 return WINED3D_OK;
2917 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2918 PLIGHTINFOEL *lightInfo = NULL;
2919 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2920 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2921 struct list *e;
2922 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2924 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2925 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2926 if(lightInfo->OriginalIndex == Index) break;
2927 lightInfo = NULL;
2930 if (lightInfo == NULL) {
2931 TRACE("Light information requested but light not defined\n");
2932 return WINED3DERR_INVALIDCALL;
2935 *pLight = lightInfo->OriginalParms;
2936 return WINED3D_OK;
2939 /*****
2940 * Get / Set Light Enable
2941 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2942 *****/
2943 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2944 PLIGHTINFOEL *lightInfo = NULL;
2945 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2946 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2947 struct list *e;
2948 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2950 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2951 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2952 if(lightInfo->OriginalIndex == Index) break;
2953 lightInfo = NULL;
2955 TRACE("Found light: %p\n", lightInfo);
2957 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2958 if (lightInfo == NULL) {
2960 TRACE("Light enabled requested but light not defined, so defining one!\n");
2961 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2963 /* Search for it again! Should be fairly quick as near head of list */
2964 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2965 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2966 if(lightInfo->OriginalIndex == Index) break;
2967 lightInfo = NULL;
2969 if (lightInfo == NULL) {
2970 FIXME("Adding default lights has failed dismally\n");
2971 return WINED3DERR_INVALIDCALL;
2975 lightInfo->enabledChanged = TRUE;
2976 if(!Enable) {
2977 if(lightInfo->glIndex != -1) {
2978 if(!This->isRecordingState) {
2979 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2982 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2983 lightInfo->glIndex = -1;
2984 } else {
2985 TRACE("Light already disabled, nothing to do\n");
2987 lightInfo->enabled = FALSE;
2988 } else {
2989 lightInfo->enabled = TRUE;
2990 if (lightInfo->glIndex != -1) {
2991 /* nop */
2992 TRACE("Nothing to do as light was enabled\n");
2993 } else {
2994 int i;
2995 /* Find a free gl light */
2996 for(i = 0; i < This->maxConcurrentLights; i++) {
2997 if(This->updateStateBlock->activeLights[i] == NULL) {
2998 This->updateStateBlock->activeLights[i] = lightInfo;
2999 lightInfo->glIndex = i;
3000 break;
3003 if(lightInfo->glIndex == -1) {
3004 /* Our tests show that Windows returns D3D_OK in this situation, even with
3005 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3006 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3007 * as well for those lights.
3009 * TODO: Test how this affects rendering
3011 WARN("Too many concurrently active lights\n");
3012 return WINED3D_OK;
3015 /* i == lightInfo->glIndex */
3016 if(!This->isRecordingState) {
3017 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3022 return WINED3D_OK;
3025 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3027 PLIGHTINFOEL *lightInfo = NULL;
3028 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3029 struct list *e;
3030 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3031 TRACE("(%p) : for idx(%d)\n", This, Index);
3033 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3034 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3035 if(lightInfo->OriginalIndex == Index) break;
3036 lightInfo = NULL;
3039 if (lightInfo == NULL) {
3040 TRACE("Light enabled state requested but light not defined\n");
3041 return WINED3DERR_INVALIDCALL;
3043 /* true is 128 according to SetLightEnable */
3044 *pEnable = lightInfo->enabled ? 128 : 0;
3045 return WINED3D_OK;
3048 /*****
3049 * Get / Set Clip Planes
3050 *****/
3051 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3052 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3053 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3055 /* Validate Index */
3056 if (Index >= GL_LIMITS(clipplanes)) {
3057 TRACE("Application has requested clipplane this device doesn't support\n");
3058 return WINED3DERR_INVALIDCALL;
3061 This->updateStateBlock->changed.clipplane |= 1 << Index;
3063 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3064 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3065 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3066 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3067 TRACE("Application is setting old values over, nothing to do\n");
3068 return WINED3D_OK;
3071 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3072 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3073 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3074 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3076 /* Handle recording of state blocks */
3077 if (This->isRecordingState) {
3078 TRACE("Recording... not performing anything\n");
3079 return WINED3D_OK;
3082 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3084 return WINED3D_OK;
3087 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3088 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3089 TRACE("(%p) : for idx %d\n", This, Index);
3091 /* Validate Index */
3092 if (Index >= GL_LIMITS(clipplanes)) {
3093 TRACE("Application has requested clipplane this device doesn't support\n");
3094 return WINED3DERR_INVALIDCALL;
3097 pPlane[0] = This->stateBlock->clipplane[Index][0];
3098 pPlane[1] = This->stateBlock->clipplane[Index][1];
3099 pPlane[2] = This->stateBlock->clipplane[Index][2];
3100 pPlane[3] = This->stateBlock->clipplane[Index][3];
3101 return WINED3D_OK;
3104 /*****
3105 * Get / Set Clip Plane Status
3106 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3107 *****/
3108 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3109 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3110 FIXME("(%p) : stub\n", This);
3111 if (NULL == pClipStatus) {
3112 return WINED3DERR_INVALIDCALL;
3114 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3115 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3116 return WINED3D_OK;
3119 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3120 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3121 FIXME("(%p) : stub\n", This);
3122 if (NULL == pClipStatus) {
3123 return WINED3DERR_INVALIDCALL;
3125 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3126 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3127 return WINED3D_OK;
3130 /*****
3131 * Get / Set Material
3132 *****/
3133 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3136 This->updateStateBlock->changed.material = TRUE;
3137 This->updateStateBlock->material = *pMaterial;
3139 /* Handle recording of state blocks */
3140 if (This->isRecordingState) {
3141 TRACE("Recording... not performing anything\n");
3142 return WINED3D_OK;
3145 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3146 return WINED3D_OK;
3149 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3150 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3151 *pMaterial = This->updateStateBlock->material;
3152 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3153 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3154 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3155 pMaterial->Ambient.b, pMaterial->Ambient.a);
3156 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3157 pMaterial->Specular.b, pMaterial->Specular.a);
3158 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3159 pMaterial->Emissive.b, pMaterial->Emissive.a);
3160 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3162 return WINED3D_OK;
3165 /*****
3166 * Get / Set Indices
3167 *****/
3168 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DBuffer* pIndexData, WINED3DFORMAT fmt) {
3169 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3170 IWineD3DBuffer *oldIdxs;
3172 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3173 oldIdxs = This->updateStateBlock->pIndexData;
3175 This->updateStateBlock->changed.indices = TRUE;
3176 This->updateStateBlock->pIndexData = pIndexData;
3177 This->updateStateBlock->IndexFmt = fmt;
3179 /* Handle recording of state blocks */
3180 if (This->isRecordingState) {
3181 TRACE("Recording... not performing anything\n");
3182 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
3183 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
3184 return WINED3D_OK;
3187 if(oldIdxs != pIndexData) {
3188 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3189 if(pIndexData) {
3190 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
3191 IWineD3DBuffer_AddRef(pIndexData);
3193 if(oldIdxs) {
3194 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
3195 IWineD3DBuffer_Release(oldIdxs);
3199 return WINED3D_OK;
3202 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DBuffer** ppIndexData) {
3203 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3205 *ppIndexData = This->stateBlock->pIndexData;
3207 /* up ref count on ppindexdata */
3208 if (*ppIndexData) {
3209 IWineD3DBuffer_AddRef(*ppIndexData);
3210 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3211 }else{
3212 TRACE("(%p) No index data set\n", This);
3214 TRACE("Returning %p\n", *ppIndexData);
3216 return WINED3D_OK;
3219 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3220 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3221 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3222 TRACE("(%p)->(%d)\n", This, BaseIndex);
3224 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3225 TRACE("Application is setting the old value over, nothing to do\n");
3226 return WINED3D_OK;
3229 This->updateStateBlock->baseVertexIndex = BaseIndex;
3231 if (This->isRecordingState) {
3232 TRACE("Recording... not performing anything\n");
3233 return WINED3D_OK;
3235 /* The base vertex index affects the stream sources */
3236 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3237 return WINED3D_OK;
3240 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3242 TRACE("(%p) : base_index %p\n", This, base_index);
3244 *base_index = This->stateBlock->baseVertexIndex;
3246 TRACE("Returning %u\n", *base_index);
3248 return WINED3D_OK;
3251 /*****
3252 * Get / Set Viewports
3253 *****/
3254 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3255 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3257 TRACE("(%p)\n", This);
3258 This->updateStateBlock->changed.viewport = TRUE;
3259 This->updateStateBlock->viewport = *pViewport;
3261 /* Handle recording of state blocks */
3262 if (This->isRecordingState) {
3263 TRACE("Recording... not performing anything\n");
3264 return WINED3D_OK;
3267 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3268 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3270 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3271 return WINED3D_OK;
3275 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3276 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3277 TRACE("(%p)\n", This);
3278 *pViewport = This->stateBlock->viewport;
3279 return WINED3D_OK;
3282 /*****
3283 * Get / Set Render States
3284 * TODO: Verify against dx9 definitions
3285 *****/
3286 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3289 DWORD oldValue = This->stateBlock->renderState[State];
3291 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3293 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3294 This->updateStateBlock->renderState[State] = Value;
3296 /* Handle recording of state blocks */
3297 if (This->isRecordingState) {
3298 TRACE("Recording... not performing anything\n");
3299 return WINED3D_OK;
3302 /* Compared here and not before the assignment to allow proper stateblock recording */
3303 if(Value == oldValue) {
3304 TRACE("Application is setting the old value over, nothing to do\n");
3305 } else {
3306 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3309 return WINED3D_OK;
3312 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3313 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3314 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3315 *pValue = This->stateBlock->renderState[State];
3316 return WINED3D_OK;
3319 /*****
3320 * Get / Set Sampler States
3321 * TODO: Verify against dx9 definitions
3322 *****/
3324 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3325 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3326 DWORD oldValue;
3328 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3329 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3331 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3332 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3335 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3336 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3337 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3340 * SetSampler is designed to allow for more than the standard up to 8 textures
3341 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3342 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3344 * http://developer.nvidia.com/object/General_FAQ.html#t6
3346 * There are two new settings for GForce
3347 * the sampler one:
3348 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3349 * and the texture one:
3350 * GL_MAX_TEXTURE_COORDS_ARB.
3351 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3352 ******************/
3354 oldValue = This->stateBlock->samplerState[Sampler][Type];
3355 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3356 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3358 /* Handle recording of state blocks */
3359 if (This->isRecordingState) {
3360 TRACE("Recording... not performing anything\n");
3361 return WINED3D_OK;
3364 if(oldValue == Value) {
3365 TRACE("Application is setting the old value over, nothing to do\n");
3366 return WINED3D_OK;
3369 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3371 return WINED3D_OK;
3374 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3375 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3377 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3378 This, Sampler, debug_d3dsamplerstate(Type), Type);
3380 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3381 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3384 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3385 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3386 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3388 *Value = This->stateBlock->samplerState[Sampler][Type];
3389 TRACE("(%p) : Returning %#x\n", This, *Value);
3391 return WINED3D_OK;
3394 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3395 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3397 This->updateStateBlock->changed.scissorRect = TRUE;
3398 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3399 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3400 return WINED3D_OK;
3402 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3404 if(This->isRecordingState) {
3405 TRACE("Recording... not performing anything\n");
3406 return WINED3D_OK;
3409 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3411 return WINED3D_OK;
3414 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3415 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3417 *pRect = This->updateStateBlock->scissorRect;
3418 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3419 return WINED3D_OK;
3422 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3423 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3424 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3426 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3428 This->updateStateBlock->vertexDecl = pDecl;
3429 This->updateStateBlock->changed.vertexDecl = TRUE;
3431 if (This->isRecordingState) {
3432 TRACE("Recording... not performing anything\n");
3433 return WINED3D_OK;
3434 } else if(pDecl == oldDecl) {
3435 /* Checked after the assignment to allow proper stateblock recording */
3436 TRACE("Application is setting the old declaration over, nothing to do\n");
3437 return WINED3D_OK;
3440 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3441 return WINED3D_OK;
3444 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3445 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3447 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3449 *ppDecl = This->stateBlock->vertexDecl;
3450 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3451 return WINED3D_OK;
3454 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3455 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3456 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3458 This->updateStateBlock->vertexShader = pShader;
3459 This->updateStateBlock->changed.vertexShader = TRUE;
3461 if (This->isRecordingState) {
3462 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3463 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3464 TRACE("Recording... not performing anything\n");
3465 return WINED3D_OK;
3466 } else if(oldShader == pShader) {
3467 /* Checked here to allow proper stateblock recording */
3468 TRACE("App is setting the old shader over, nothing to do\n");
3469 return WINED3D_OK;
3472 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3473 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3474 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3476 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3478 return WINED3D_OK;
3481 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3482 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3484 if (NULL == ppShader) {
3485 return WINED3DERR_INVALIDCALL;
3487 *ppShader = This->stateBlock->vertexShader;
3488 if( NULL != *ppShader)
3489 IWineD3DVertexShader_AddRef(*ppShader);
3491 TRACE("(%p) : returning %p\n", This, *ppShader);
3492 return WINED3D_OK;
3495 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3496 IWineD3DDevice *iface,
3497 UINT start,
3498 CONST BOOL *srcData,
3499 UINT count) {
3501 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3502 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3504 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3505 iface, srcData, start, count);
3507 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3509 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3510 for (i = 0; i < cnt; i++)
3511 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3513 for (i = start; i < cnt + start; ++i) {
3514 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3517 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3519 return WINED3D_OK;
3522 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3523 IWineD3DDevice *iface,
3524 UINT start,
3525 BOOL *dstData,
3526 UINT count) {
3528 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3529 int cnt = min(count, MAX_CONST_B - start);
3531 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3532 iface, dstData, start, count);
3534 if (dstData == NULL || cnt < 0)
3535 return WINED3DERR_INVALIDCALL;
3537 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3538 return WINED3D_OK;
3541 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3542 IWineD3DDevice *iface,
3543 UINT start,
3544 CONST int *srcData,
3545 UINT count) {
3547 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3548 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3550 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3551 iface, srcData, start, count);
3553 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3555 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3556 for (i = 0; i < cnt; i++)
3557 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3558 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3560 for (i = start; i < cnt + start; ++i) {
3561 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3564 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3566 return WINED3D_OK;
3569 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3570 IWineD3DDevice *iface,
3571 UINT start,
3572 int *dstData,
3573 UINT count) {
3575 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3576 int cnt = min(count, MAX_CONST_I - start);
3578 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3579 iface, dstData, start, count);
3581 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3582 return WINED3DERR_INVALIDCALL;
3584 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3585 return WINED3D_OK;
3588 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3589 IWineD3DDevice *iface,
3590 UINT start,
3591 CONST float *srcData,
3592 UINT count) {
3594 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3595 UINT i;
3597 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3598 iface, srcData, start, count);
3600 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3601 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3602 return WINED3DERR_INVALIDCALL;
3604 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3605 if(TRACE_ON(d3d)) {
3606 for (i = 0; i < count; i++)
3607 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3608 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3611 if (!This->isRecordingState)
3613 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3614 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3617 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3618 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3620 return WINED3D_OK;
3623 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3624 IWineD3DDevice *iface,
3625 UINT start,
3626 float *dstData,
3627 UINT count) {
3629 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3630 int cnt = min(count, This->d3d_vshader_constantF - start);
3632 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3633 iface, dstData, start, count);
3635 if (dstData == NULL || cnt < 0)
3636 return WINED3DERR_INVALIDCALL;
3638 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3639 return WINED3D_OK;
3642 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3643 DWORD i;
3644 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3646 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3650 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3651 int i = This->rev_tex_unit_map[unit];
3652 int j = This->texUnitMap[stage];
3654 This->texUnitMap[stage] = unit;
3655 if (i != -1 && i != stage) {
3656 This->texUnitMap[i] = -1;
3659 This->rev_tex_unit_map[unit] = stage;
3660 if (j != -1 && j != unit) {
3661 This->rev_tex_unit_map[j] = -1;
3665 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3666 int i;
3668 This->fixed_function_usage_map = 0;
3669 for (i = 0; i < MAX_TEXTURES; ++i) {
3670 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3671 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3672 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3673 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3674 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3675 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3676 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3677 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3679 if (color_op == WINED3DTOP_DISABLE) {
3680 /* Not used, and disable higher stages */
3681 break;
3684 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3685 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3686 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3687 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3688 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3689 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3690 This->fixed_function_usage_map |= (1 << i);
3693 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3694 This->fixed_function_usage_map |= (1 << (i + 1));
3699 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3700 unsigned int i, tex;
3701 WORD ffu_map;
3703 device_update_fixed_function_usage_map(This);
3704 ffu_map = This->fixed_function_usage_map;
3706 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3707 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3708 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3710 if (!(ffu_map & 1)) continue;
3712 if (This->texUnitMap[i] != i) {
3713 device_map_stage(This, i, i);
3714 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3715 markTextureStagesDirty(This, i);
3718 return;
3721 /* Now work out the mapping */
3722 tex = 0;
3723 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3725 if (!(ffu_map & 1)) continue;
3727 if (This->texUnitMap[i] != tex) {
3728 device_map_stage(This, i, tex);
3729 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3730 markTextureStagesDirty(This, i);
3733 ++tex;
3737 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3738 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3739 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3740 unsigned int i;
3742 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3743 if (sampler_type[i] && This->texUnitMap[i] != i)
3745 device_map_stage(This, i, i);
3746 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3747 if (i < MAX_TEXTURES) {
3748 markTextureStagesDirty(This, i);
3754 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3755 const DWORD *vshader_sampler_tokens, int unit)
3757 int current_mapping = This->rev_tex_unit_map[unit];
3759 if (current_mapping == -1) {
3760 /* Not currently used */
3761 return TRUE;
3764 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3765 /* Used by a fragment sampler */
3767 if (!pshader_sampler_tokens) {
3768 /* No pixel shader, check fixed function */
3769 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3772 /* Pixel shader, check the shader's sampler map */
3773 return !pshader_sampler_tokens[current_mapping];
3776 /* Used by a vertex sampler */
3777 return !vshader_sampler_tokens[current_mapping];
3780 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3781 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3782 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3783 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3784 int start = GL_LIMITS(combined_samplers) - 1;
3785 int i;
3787 if (ps) {
3788 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3790 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3791 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3792 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3795 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3796 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3797 if (vshader_sampler_type[i])
3799 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3801 /* Already mapped somewhere */
3802 continue;
3805 while (start >= 0) {
3806 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3808 device_map_stage(This, vsampler_idx, start);
3809 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3811 --start;
3812 break;
3815 --start;
3821 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3822 BOOL vs = use_vs(This->stateBlock);
3823 BOOL ps = use_ps(This->stateBlock);
3825 * Rules are:
3826 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3827 * that would be really messy and require shader recompilation
3828 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3829 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3831 if (ps) {
3832 device_map_psamplers(This);
3833 } else {
3834 device_map_fixed_function_samplers(This);
3837 if (vs) {
3838 device_map_vsamplers(This, ps);
3842 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3843 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3844 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3845 This->updateStateBlock->pixelShader = pShader;
3846 This->updateStateBlock->changed.pixelShader = TRUE;
3848 /* Handle recording of state blocks */
3849 if (This->isRecordingState) {
3850 TRACE("Recording... not performing anything\n");
3853 if (This->isRecordingState) {
3854 TRACE("Recording... not performing anything\n");
3855 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3856 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3857 return WINED3D_OK;
3860 if(pShader == oldShader) {
3861 TRACE("App is setting the old pixel shader over, nothing to do\n");
3862 return WINED3D_OK;
3865 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3866 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3868 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3869 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3871 return WINED3D_OK;
3874 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3875 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3877 if (NULL == ppShader) {
3878 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3879 return WINED3DERR_INVALIDCALL;
3882 *ppShader = This->stateBlock->pixelShader;
3883 if (NULL != *ppShader) {
3884 IWineD3DPixelShader_AddRef(*ppShader);
3886 TRACE("(%p) : returning %p\n", This, *ppShader);
3887 return WINED3D_OK;
3890 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3891 IWineD3DDevice *iface,
3892 UINT start,
3893 CONST BOOL *srcData,
3894 UINT count) {
3896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3897 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3899 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3900 iface, srcData, start, count);
3902 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3904 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3905 for (i = 0; i < cnt; i++)
3906 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3908 for (i = start; i < cnt + start; ++i) {
3909 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3912 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3914 return WINED3D_OK;
3917 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3918 IWineD3DDevice *iface,
3919 UINT start,
3920 BOOL *dstData,
3921 UINT count) {
3923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3924 int cnt = min(count, MAX_CONST_B - start);
3926 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3927 iface, dstData, start, count);
3929 if (dstData == NULL || cnt < 0)
3930 return WINED3DERR_INVALIDCALL;
3932 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3933 return WINED3D_OK;
3936 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3937 IWineD3DDevice *iface,
3938 UINT start,
3939 CONST int *srcData,
3940 UINT count) {
3942 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3943 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3945 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3946 iface, srcData, start, count);
3948 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3950 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3951 for (i = 0; i < cnt; i++)
3952 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3953 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3955 for (i = start; i < cnt + start; ++i) {
3956 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3959 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3961 return WINED3D_OK;
3964 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3965 IWineD3DDevice *iface,
3966 UINT start,
3967 int *dstData,
3968 UINT count) {
3970 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3971 int cnt = min(count, MAX_CONST_I - start);
3973 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3974 iface, dstData, start, count);
3976 if (dstData == NULL || cnt < 0)
3977 return WINED3DERR_INVALIDCALL;
3979 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3980 return WINED3D_OK;
3983 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3984 IWineD3DDevice *iface,
3985 UINT start,
3986 CONST float *srcData,
3987 UINT count) {
3989 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3990 UINT i;
3992 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3993 iface, srcData, start, count);
3995 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3996 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3997 return WINED3DERR_INVALIDCALL;
3999 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4000 if(TRACE_ON(d3d)) {
4001 for (i = 0; i < count; i++)
4002 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4003 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4006 if (!This->isRecordingState)
4008 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
4009 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4012 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
4013 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
4015 return WINED3D_OK;
4018 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4019 IWineD3DDevice *iface,
4020 UINT start,
4021 float *dstData,
4022 UINT count) {
4024 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4025 int cnt = min(count, This->d3d_pshader_constantF - start);
4027 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4028 iface, dstData, start, count);
4030 if (dstData == NULL || cnt < 0)
4031 return WINED3DERR_INVALIDCALL;
4033 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4034 return WINED3D_OK;
4037 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4038 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4039 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
4040 DWORD DestFVF)
4042 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4043 unsigned int i;
4044 WINED3DVIEWPORT vp;
4045 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4046 BOOL doClip;
4047 DWORD numTextures;
4049 if (stream_info->elements[WINED3D_FFP_NORMAL].data)
4051 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4054 if (!stream_info->elements[WINED3D_FFP_POSITION].data)
4056 ERR("Source has no position mask\n");
4057 return WINED3DERR_INVALIDCALL;
4060 /* We might access VBOs from this code, so hold the lock */
4061 ENTER_GL();
4063 if (dest->resource.allocatedMemory == NULL) {
4064 buffer_get_sysmem(dest);
4067 /* Get a pointer into the destination vbo(create one if none exists) and
4068 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4070 if (!dest->buffer_object && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT))
4072 dest->flags |= WINED3D_BUFFER_CREATEBO;
4073 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
4076 if (dest->buffer_object)
4078 unsigned char extrabytes = 0;
4079 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4080 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4081 * this may write 4 extra bytes beyond the area that should be written
4083 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4084 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4085 if(!dest_conv_addr) {
4086 ERR("Out of memory\n");
4087 /* Continue without storing converted vertices */
4089 dest_conv = dest_conv_addr;
4092 /* Should I clip?
4093 * a) WINED3DRS_CLIPPING is enabled
4094 * b) WINED3DVOP_CLIP is passed
4096 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4097 static BOOL warned = FALSE;
4099 * The clipping code is not quite correct. Some things need
4100 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4101 * so disable clipping for now.
4102 * (The graphics in Half-Life are broken, and my processvertices
4103 * test crashes with IDirect3DDevice3)
4104 doClip = TRUE;
4106 doClip = FALSE;
4107 if(!warned) {
4108 warned = TRUE;
4109 FIXME("Clipping is broken and disabled for now\n");
4111 } else doClip = FALSE;
4112 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4114 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4115 WINED3DTS_VIEW,
4116 &view_mat);
4117 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4118 WINED3DTS_PROJECTION,
4119 &proj_mat);
4120 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4121 WINED3DTS_WORLDMATRIX(0),
4122 &world_mat);
4124 TRACE("View mat:\n");
4125 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);
4126 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);
4127 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);
4128 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);
4130 TRACE("Proj mat:\n");
4131 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);
4132 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);
4133 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);
4134 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);
4136 TRACE("World mat:\n");
4137 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);
4138 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);
4139 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);
4140 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);
4142 /* Get the viewport */
4143 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4144 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4145 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4147 multiply_matrix(&mat,&view_mat,&world_mat);
4148 multiply_matrix(&mat,&proj_mat,&mat);
4150 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4152 for (i = 0; i < dwCount; i+= 1) {
4153 unsigned int tex_index;
4155 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4156 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4157 /* The position first */
4158 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
4159 const float *p = (const float *)(element->data + i * element->stride);
4160 float x, y, z, rhw;
4161 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4163 /* Multiplication with world, view and projection matrix */
4164 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);
4165 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);
4166 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);
4167 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);
4169 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4171 /* WARNING: The following things are taken from d3d7 and were not yet checked
4172 * against d3d8 or d3d9!
4175 /* Clipping conditions: From msdn
4177 * A vertex is clipped if it does not match the following requirements
4178 * -rhw < x <= rhw
4179 * -rhw < y <= rhw
4180 * 0 < z <= rhw
4181 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4183 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4184 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4188 if( !doClip ||
4189 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4190 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4191 ( rhw > eps ) ) ) {
4193 /* "Normal" viewport transformation (not clipped)
4194 * 1) The values are divided by rhw
4195 * 2) The y axis is negative, so multiply it with -1
4196 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4197 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4198 * 4) Multiply x with Width/2 and add Width/2
4199 * 5) The same for the height
4200 * 6) Add the viewpoint X and Y to the 2D coordinates and
4201 * The minimum Z value to z
4202 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4204 * Well, basically it's simply a linear transformation into viewport
4205 * coordinates
4208 x /= rhw;
4209 y /= rhw;
4210 z /= rhw;
4212 y *= -1;
4214 x *= vp.Width / 2;
4215 y *= vp.Height / 2;
4216 z *= vp.MaxZ - vp.MinZ;
4218 x += vp.Width / 2 + vp.X;
4219 y += vp.Height / 2 + vp.Y;
4220 z += vp.MinZ;
4222 rhw = 1 / rhw;
4223 } else {
4224 /* That vertex got clipped
4225 * Contrary to OpenGL it is not dropped completely, it just
4226 * undergoes a different calculation.
4228 TRACE("Vertex got clipped\n");
4229 x += rhw;
4230 y += rhw;
4232 x /= 2;
4233 y /= 2;
4235 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4236 * outside of the main vertex buffer memory. That needs some more
4237 * investigation...
4241 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4244 ( (float *) dest_ptr)[0] = x;
4245 ( (float *) dest_ptr)[1] = y;
4246 ( (float *) dest_ptr)[2] = z;
4247 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4249 dest_ptr += 3 * sizeof(float);
4251 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4252 dest_ptr += sizeof(float);
4255 if(dest_conv) {
4256 float w = 1 / rhw;
4257 ( (float *) dest_conv)[0] = x * w;
4258 ( (float *) dest_conv)[1] = y * w;
4259 ( (float *) dest_conv)[2] = z * w;
4260 ( (float *) dest_conv)[3] = w;
4262 dest_conv += 3 * sizeof(float);
4264 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4265 dest_conv += sizeof(float);
4269 if (DestFVF & WINED3DFVF_PSIZE) {
4270 dest_ptr += sizeof(DWORD);
4271 if(dest_conv) dest_conv += sizeof(DWORD);
4273 if (DestFVF & WINED3DFVF_NORMAL) {
4274 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4275 const float *normal = (const float *)(element->data + i * element->stride);
4276 /* AFAIK this should go into the lighting information */
4277 FIXME("Didn't expect the destination to have a normal\n");
4278 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4279 if(dest_conv) {
4280 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4284 if (DestFVF & WINED3DFVF_DIFFUSE) {
4285 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4286 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4287 if(!color_d) {
4288 static BOOL warned = FALSE;
4290 if(!warned) {
4291 ERR("No diffuse color in source, but destination has one\n");
4292 warned = TRUE;
4295 *( (DWORD *) dest_ptr) = 0xffffffff;
4296 dest_ptr += sizeof(DWORD);
4298 if(dest_conv) {
4299 *( (DWORD *) dest_conv) = 0xffffffff;
4300 dest_conv += sizeof(DWORD);
4303 else {
4304 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4305 if(dest_conv) {
4306 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4307 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4308 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4309 dest_conv += sizeof(DWORD);
4314 if (DestFVF & WINED3DFVF_SPECULAR) {
4315 /* What's the color value in the feedback buffer? */
4316 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4317 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4318 if(!color_s) {
4319 static BOOL warned = FALSE;
4321 if(!warned) {
4322 ERR("No specular color in source, but destination has one\n");
4323 warned = TRUE;
4326 *( (DWORD *) dest_ptr) = 0xFF000000;
4327 dest_ptr += sizeof(DWORD);
4329 if(dest_conv) {
4330 *( (DWORD *) dest_conv) = 0xFF000000;
4331 dest_conv += sizeof(DWORD);
4334 else {
4335 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4336 if(dest_conv) {
4337 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4338 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4339 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4340 dest_conv += sizeof(DWORD);
4345 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4346 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4347 const float *tex_coord = (const float *)(element->data + i * element->stride);
4348 if(!tex_coord) {
4349 ERR("No source texture, but destination requests one\n");
4350 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4351 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4353 else {
4354 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4355 if(dest_conv) {
4356 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4362 if(dest_conv) {
4363 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4364 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4365 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4366 dwCount * get_flexible_vertex_size(DestFVF),
4367 dest_conv_addr));
4368 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4369 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4372 LEAVE_GL();
4374 return WINED3D_OK;
4376 #undef copy_and_next
4378 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4379 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4380 DWORD DestFVF)
4382 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4383 struct wined3d_stream_info stream_info;
4384 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4385 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4387 if(pVertexDecl) {
4388 ERR("Output vertex declaration not implemented yet\n");
4391 /* Need any context to write to the vbo. */
4392 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4394 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4395 * control the streamIsUP flag, thus restore it afterwards.
4397 This->stateBlock->streamIsUP = FALSE;
4398 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4399 This->stateBlock->streamIsUP = streamWasUP;
4401 if(vbo || SrcStartIndex) {
4402 unsigned int i;
4403 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4404 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4406 * Also get the start index in, but only loop over all elements if there's something to add at all.
4408 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4410 struct wined3d_stream_info_element *e = &stream_info.elements[i];
4411 if (e->buffer_object)
4413 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
4414 e->buffer_object = 0;
4415 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
4416 ENTER_GL();
4417 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4418 vb->buffer_object = 0;
4419 LEAVE_GL();
4421 if (e->data) e->data += e->stride * SrcStartIndex;
4425 return process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4426 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4429 /*****
4430 * Get / Set Texture Stage States
4431 * TODO: Verify against dx9 definitions
4432 *****/
4433 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4434 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4435 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4437 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4439 if (Stage >= MAX_TEXTURES) {
4440 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4441 return WINED3D_OK;
4444 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4445 This->updateStateBlock->textureState[Stage][Type] = Value;
4447 if (This->isRecordingState) {
4448 TRACE("Recording... not performing anything\n");
4449 return WINED3D_OK;
4452 /* Checked after the assignments to allow proper stateblock recording */
4453 if(oldValue == Value) {
4454 TRACE("App is setting the old value over, nothing to do\n");
4455 return WINED3D_OK;
4458 if(Stage > This->stateBlock->lowest_disabled_stage &&
4459 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4460 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4461 * Changes in other states are important on disabled stages too
4463 return WINED3D_OK;
4466 if(Type == WINED3DTSS_COLOROP) {
4467 unsigned int i;
4469 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4470 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4471 * they have to be disabled
4473 * The current stage is dirtified below.
4475 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4476 TRACE("Additionally dirtifying stage %u\n", i);
4477 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4479 This->stateBlock->lowest_disabled_stage = Stage;
4480 TRACE("New lowest disabled: %u\n", Stage);
4481 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4482 /* Previously disabled stage enabled. Stages above it may need enabling
4483 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4484 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4486 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4489 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4490 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4491 break;
4493 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4494 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4496 This->stateBlock->lowest_disabled_stage = i;
4497 TRACE("New lowest disabled: %u\n", i);
4501 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4503 return WINED3D_OK;
4506 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4507 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4508 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4509 *pValue = This->updateStateBlock->textureState[Stage][Type];
4510 return WINED3D_OK;
4513 /*****
4514 * Get / Set Texture
4515 *****/
4516 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4517 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4518 IWineD3DBaseTexture *oldTexture;
4520 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4522 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4523 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4526 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4527 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4528 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4531 oldTexture = This->updateStateBlock->textures[Stage];
4533 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4534 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
4536 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4537 return WINED3DERR_INVALIDCALL;
4540 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4541 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4543 This->updateStateBlock->changed.textures |= 1 << Stage;
4544 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4545 This->updateStateBlock->textures[Stage] = pTexture;
4547 /* Handle recording of state blocks */
4548 if (This->isRecordingState) {
4549 TRACE("Recording... not performing anything\n");
4550 return WINED3D_OK;
4553 if(oldTexture == pTexture) {
4554 TRACE("App is setting the same texture again, nothing to do\n");
4555 return WINED3D_OK;
4558 /** NOTE: MSDN says that setTexture increases the reference count,
4559 * and that the application must set the texture back to null (or have a leaky application),
4560 * This means we should pass the refcount up to the parent
4561 *******************************/
4562 if (NULL != This->updateStateBlock->textures[Stage]) {
4563 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4564 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4565 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4567 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4569 if (!oldTexture || dimensions != IWineD3DBaseTexture_GetTextureDimensions(oldTexture))
4571 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4574 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4575 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4576 * so the COLOROP and ALPHAOP have to be dirtified.
4578 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4579 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4581 if(bindCount == 1) {
4582 new->baseTexture.sampler = Stage;
4584 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4588 if (NULL != oldTexture) {
4589 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4590 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4592 IWineD3DBaseTexture_Release(oldTexture);
4593 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4594 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4595 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4598 if(bindCount && old->baseTexture.sampler == Stage) {
4599 int i;
4600 /* Have to do a search for the other sampler(s) where the texture is bound to
4601 * Shouldn't happen as long as apps bind a texture only to one stage
4603 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4604 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4605 if(This->updateStateBlock->textures[i] == oldTexture) {
4606 old->baseTexture.sampler = i;
4607 break;
4613 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4615 return WINED3D_OK;
4618 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4619 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4621 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4623 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4624 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4627 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4628 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4629 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4632 *ppTexture=This->stateBlock->textures[Stage];
4633 if (*ppTexture)
4634 IWineD3DBaseTexture_AddRef(*ppTexture);
4636 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4638 return WINED3D_OK;
4641 /*****
4642 * Get Back Buffer
4643 *****/
4644 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4645 IWineD3DSurface **ppBackBuffer) {
4646 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4647 IWineD3DSwapChain *swapChain;
4648 HRESULT hr;
4650 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4652 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4653 if (hr == WINED3D_OK) {
4654 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4655 IWineD3DSwapChain_Release(swapChain);
4656 } else {
4657 *ppBackBuffer = NULL;
4659 return hr;
4662 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4663 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4664 WARN("(%p) : stub, calling idirect3d for now\n", This);
4665 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4668 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4669 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4670 IWineD3DSwapChain *swapChain;
4671 HRESULT hr;
4673 if(iSwapChain > 0) {
4674 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4675 if (hr == WINED3D_OK) {
4676 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4677 IWineD3DSwapChain_Release(swapChain);
4678 } else {
4679 FIXME("(%p) Error getting display mode\n", This);
4681 } else {
4682 /* Don't read the real display mode,
4683 but return the stored mode instead. X11 can't change the color
4684 depth, and some apps are pretty angry if they SetDisplayMode from
4685 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4687 Also don't relay to the swapchain because with ddraw it's possible
4688 that there isn't a swapchain at all */
4689 pMode->Width = This->ddraw_width;
4690 pMode->Height = This->ddraw_height;
4691 pMode->Format = This->ddraw_format;
4692 pMode->RefreshRate = 0;
4693 hr = WINED3D_OK;
4696 return hr;
4699 /*****
4700 * Stateblock related functions
4701 *****/
4703 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4704 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4705 IWineD3DStateBlock *stateblock;
4706 HRESULT hr;
4708 TRACE("(%p)\n", This);
4710 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4712 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4713 if (FAILED(hr)) return hr;
4715 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4716 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4717 This->isRecordingState = TRUE;
4719 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4721 return WINED3D_OK;
4724 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4726 unsigned int i, j;
4727 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4729 if (!This->isRecordingState) {
4730 WARN("(%p) not recording! returning error\n", This);
4731 *ppStateBlock = NULL;
4732 return WINED3DERR_INVALIDCALL;
4735 for (i = 0; i <= WINEHIGHEST_RENDER_STATE >> 5; ++i)
4737 DWORD map = object->changed.renderState[i];
4738 for (j = 0; map; map >>= 1, ++j)
4740 if (!(map & 1)) continue;
4742 object->contained_render_states[object->num_contained_render_states++] = (i << 5) | j;
4746 for (i = 0; i <= HIGHEST_TRANSFORMSTATE >> 5; ++i)
4748 DWORD map = object->changed.transform[i];
4749 for (j = 0; map; map >>= 1, ++j)
4751 if (!(map & 1)) continue;
4753 object->contained_transform_states[object->num_contained_transform_states++] = (i << 5) | j;
4756 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4757 if(object->changed.vertexShaderConstantsF[i]) {
4758 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4759 object->num_contained_vs_consts_f++;
4762 for(i = 0; i < MAX_CONST_I; i++) {
4763 if (object->changed.vertexShaderConstantsI & (1 << i))
4765 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4766 object->num_contained_vs_consts_i++;
4769 for(i = 0; i < MAX_CONST_B; i++) {
4770 if (object->changed.vertexShaderConstantsB & (1 << i))
4772 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4773 object->num_contained_vs_consts_b++;
4776 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
4778 if (object->changed.pixelShaderConstantsF[i])
4780 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
4781 ++object->num_contained_ps_consts_f;
4784 for(i = 0; i < MAX_CONST_I; i++) {
4785 if (object->changed.pixelShaderConstantsI & (1 << i))
4787 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4788 object->num_contained_ps_consts_i++;
4791 for(i = 0; i < MAX_CONST_B; i++) {
4792 if (object->changed.pixelShaderConstantsB & (1 << i))
4794 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4795 object->num_contained_ps_consts_b++;
4798 for(i = 0; i < MAX_TEXTURES; i++) {
4799 DWORD map = object->changed.textureState[i];
4801 for(j = 0; map; map >>= 1, ++j)
4803 if (!(map & 1)) continue;
4805 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4806 object->contained_tss_states[object->num_contained_tss_states].state = j;
4807 ++object->num_contained_tss_states;
4810 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4811 DWORD map = object->changed.samplerState[i];
4813 for (j = 0; map; map >>= 1, ++j)
4815 if (!(map & 1)) continue;
4817 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4818 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4819 ++object->num_contained_sampler_states;
4823 *ppStateBlock = (IWineD3DStateBlock*) object;
4824 This->isRecordingState = FALSE;
4825 This->updateStateBlock = This->stateBlock;
4826 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4827 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4828 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4829 return WINED3D_OK;
4832 /*****
4833 * Scene related functions
4834 *****/
4835 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4836 /* At the moment we have no need for any functionality at the beginning
4837 of a scene */
4838 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4839 TRACE("(%p)\n", This);
4841 if(This->inScene) {
4842 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4843 return WINED3DERR_INVALIDCALL;
4845 This->inScene = TRUE;
4846 return WINED3D_OK;
4849 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4850 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4851 TRACE("(%p)\n", This);
4853 if(!This->inScene) {
4854 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4855 return WINED3DERR_INVALIDCALL;
4858 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4859 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4860 glFlush();
4861 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4862 * fails
4865 This->inScene = FALSE;
4866 return WINED3D_OK;
4869 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4870 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4871 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4872 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4873 IWineD3DSwapChain *swapChain = NULL;
4874 int i;
4875 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4877 TRACE("(%p) Presenting the frame\n", This);
4879 for(i = 0 ; i < swapchains ; i ++) {
4881 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4882 TRACE("presentinng chain %d, %p\n", i, swapChain);
4883 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4884 IWineD3DSwapChain_Release(swapChain);
4887 return WINED3D_OK;
4890 /* Not called from the VTable (internal subroutine) */
4891 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4892 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4893 float Z, DWORD Stencil) {
4894 GLbitfield glMask = 0;
4895 unsigned int i;
4896 WINED3DRECT curRect;
4897 RECT vp_rect;
4898 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4899 UINT drawable_width, drawable_height;
4900 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4901 IWineD3DSwapChainImpl *swapchain = NULL;
4903 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4904 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4905 * for the cleared parts, and the untouched parts.
4907 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4908 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4909 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4910 * checking all this if the dest surface is in the drawable anyway.
4912 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4913 while(1) {
4914 if(vp->X != 0 || vp->Y != 0 ||
4915 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4916 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4917 break;
4919 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4920 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4921 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4922 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4923 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4924 break;
4926 if(Count > 0 && pRects && (
4927 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4928 pRects[0].x2 < target->currentDesc.Width ||
4929 pRects[0].y2 < target->currentDesc.Height)) {
4930 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4931 break;
4933 break;
4937 target->get_drawable_size(target, &drawable_width, &drawable_height);
4939 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
4940 ENTER_GL();
4942 /* Only set the values up once, as they are not changing */
4943 if (Flags & WINED3DCLEAR_STENCIL) {
4944 glClearStencil(Stencil);
4945 checkGLcall("glClearStencil");
4946 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4947 glStencilMask(0xFFFFFFFF);
4950 if (Flags & WINED3DCLEAR_ZBUFFER) {
4951 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4952 glDepthMask(GL_TRUE);
4953 glClearDepth(Z);
4954 checkGLcall("glClearDepth");
4955 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4956 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4958 if (vp->X != 0 || vp->Y != 0 ||
4959 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4960 surface_load_ds_location(This->stencilBufferTarget, location);
4962 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4963 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4964 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4965 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4966 surface_load_ds_location(This->stencilBufferTarget, location);
4968 else if (Count > 0 && pRects && (
4969 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4970 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4971 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4972 surface_load_ds_location(This->stencilBufferTarget, location);
4976 if (Flags & WINED3DCLEAR_TARGET) {
4977 TRACE("Clearing screen with glClear to color %x\n", Color);
4978 glClearColor(D3DCOLOR_R(Color),
4979 D3DCOLOR_G(Color),
4980 D3DCOLOR_B(Color),
4981 D3DCOLOR_A(Color));
4982 checkGLcall("glClearColor");
4984 /* Clear ALL colors! */
4985 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4986 glMask = glMask | GL_COLOR_BUFFER_BIT;
4989 vp_rect.left = vp->X;
4990 vp_rect.top = vp->Y;
4991 vp_rect.right = vp->X + vp->Width;
4992 vp_rect.bottom = vp->Y + vp->Height;
4993 if (!(Count > 0 && pRects)) {
4994 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4995 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4997 if(This->render_offscreen) {
4998 glScissor(vp_rect.left, vp_rect.top,
4999 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5000 } else {
5001 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5002 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5004 checkGLcall("glScissor");
5005 glClear(glMask);
5006 checkGLcall("glClear");
5007 } else {
5008 /* Now process each rect in turn */
5009 for (i = 0; i < Count; i++) {
5010 /* Note gl uses lower left, width/height */
5011 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5012 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5013 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5015 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5016 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5017 curRect.x1, (target->currentDesc.Height - curRect.y2),
5018 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5020 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5021 * The rectangle is not cleared, no error is returned, but further rectanlges are
5022 * still cleared if they are valid
5024 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5025 TRACE("Rectangle with negative dimensions, ignoring\n");
5026 continue;
5029 if(This->render_offscreen) {
5030 glScissor(curRect.x1, curRect.y1,
5031 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5032 } else {
5033 glScissor(curRect.x1, drawable_height - curRect.y2,
5034 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5036 checkGLcall("glScissor");
5038 glClear(glMask);
5039 checkGLcall("glClear");
5043 /* Restore the old values (why..?) */
5044 if (Flags & WINED3DCLEAR_STENCIL) {
5045 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5047 if (Flags & WINED3DCLEAR_TARGET) {
5048 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5049 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5050 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5051 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5052 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5054 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5055 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5057 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5059 if (Flags & WINED3DCLEAR_ZBUFFER) {
5060 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5061 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5062 surface_modify_ds_location(This->stencilBufferTarget, location);
5065 LEAVE_GL();
5067 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5068 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5069 glFlush();
5071 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5074 return WINED3D_OK;
5077 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5078 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5079 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5080 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5082 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5083 Count, pRects, Flags, Color, Z, Stencil);
5085 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5086 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5087 /* TODO: What about depth stencil buffers without stencil bits? */
5088 return WINED3DERR_INVALIDCALL;
5091 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5094 /*****
5095 * Drawing functions
5096 *****/
5098 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
5099 WINED3DPRIMITIVETYPE primitive_type)
5101 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5103 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
5105 This->updateStateBlock->changed.primitive_type = TRUE;
5106 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
5109 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
5110 WINED3DPRIMITIVETYPE *primitive_type)
5112 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5114 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
5116 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
5118 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
5121 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
5123 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5125 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
5127 if(!This->stateBlock->vertexDecl) {
5128 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5129 return WINED3DERR_INVALIDCALL;
5132 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5133 if(This->stateBlock->streamIsUP) {
5134 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5135 This->stateBlock->streamIsUP = FALSE;
5138 if(This->stateBlock->loadBaseVertexIndex != 0) {
5139 This->stateBlock->loadBaseVertexIndex = 0;
5140 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5142 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5143 drawPrimitive(iface, vertex_count, 0/* NumVertices */, StartVertex /* start_idx */,
5144 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5145 return WINED3D_OK;
5148 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5149 UINT minIndex, UINT NumVertices, UINT startIndex, UINT index_count)
5151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5152 UINT idxStride = 2;
5153 IWineD3DBuffer *pIB;
5154 GLuint vbo;
5156 pIB = This->stateBlock->pIndexData;
5157 if (!pIB) {
5158 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5159 * without an index buffer set. (The first time at least...)
5160 * D3D8 simply dies, but I doubt it can do much harm to return
5161 * D3DERR_INVALIDCALL there as well. */
5162 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5163 return WINED3DERR_INVALIDCALL;
5166 if(!This->stateBlock->vertexDecl) {
5167 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5168 return WINED3DERR_INVALIDCALL;
5171 if(This->stateBlock->streamIsUP) {
5172 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5173 This->stateBlock->streamIsUP = FALSE;
5175 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
5177 TRACE("(%p) : min %u, vertex count %u, startIdx %u, index count %u\n",
5178 This, minIndex, NumVertices, startIndex, index_count);
5180 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
5181 idxStride = 2;
5182 } else {
5183 idxStride = 4;
5186 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5187 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5188 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5191 drawPrimitive(iface, index_count, NumVertices, startIndex, idxStride,
5192 vbo ? NULL : ((struct wined3d_buffer *) pIB)->resource.allocatedMemory, minIndex);
5194 return WINED3D_OK;
5197 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
5198 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5200 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5201 IWineD3DBuffer *vb;
5203 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
5204 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
5206 if(!This->stateBlock->vertexDecl) {
5207 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5208 return WINED3DERR_INVALIDCALL;
5211 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5212 vb = This->stateBlock->streamSource[0];
5213 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5214 if (vb) IWineD3DBuffer_Release(vb);
5215 This->stateBlock->streamOffset[0] = 0;
5216 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5217 This->stateBlock->streamIsUP = TRUE;
5218 This->stateBlock->loadBaseVertexIndex = 0;
5220 /* TODO: Only mark dirty if drawing from a different UP address */
5221 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5223 drawPrimitive(iface, vertex_count, 0 /* NumVertices */, 0 /* start_idx */,
5224 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5226 /* MSDN specifies stream zero settings must be set to NULL */
5227 This->stateBlock->streamStride[0] = 0;
5228 This->stateBlock->streamSource[0] = NULL;
5230 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5231 * the new stream sources or use UP drawing again
5233 return WINED3D_OK;
5236 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, UINT MinVertexIndex,
5237 UINT NumVertices, UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
5238 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5240 int idxStride;
5241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5242 IWineD3DBuffer *vb;
5243 IWineD3DBuffer *ib;
5245 TRACE("(%p) : MinVtxIdx %u, NumVIdx %u, index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u\n",
5246 This, MinVertexIndex, NumVertices, index_count, pIndexData,
5247 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5249 if(!This->stateBlock->vertexDecl) {
5250 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5251 return WINED3DERR_INVALIDCALL;
5254 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
5255 idxStride = 2;
5256 } else {
5257 idxStride = 4;
5260 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5261 vb = This->stateBlock->streamSource[0];
5262 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5263 if (vb) IWineD3DBuffer_Release(vb);
5264 This->stateBlock->streamIsUP = TRUE;
5265 This->stateBlock->streamOffset[0] = 0;
5266 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5268 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5269 This->stateBlock->baseVertexIndex = 0;
5270 This->stateBlock->loadBaseVertexIndex = 0;
5271 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5272 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5273 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5275 drawPrimitive(iface, index_count, NumVertices, 0 /* start_idx */,
5276 idxStride, pIndexData, MinVertexIndex);
5278 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5279 This->stateBlock->streamSource[0] = NULL;
5280 This->stateBlock->streamStride[0] = 0;
5281 ib = This->stateBlock->pIndexData;
5282 if(ib) {
5283 IWineD3DBuffer_Release(ib);
5284 This->stateBlock->pIndexData = NULL;
5286 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5287 * SetStreamSource to specify a vertex buffer
5290 return WINED3D_OK;
5293 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5294 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
5296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5298 /* Mark the state dirty until we have nicer tracking
5299 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5300 * that value.
5302 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5303 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5304 This->stateBlock->baseVertexIndex = 0;
5305 This->up_strided = DrawPrimStrideData;
5306 drawPrimitive(iface, vertex_count, 0, 0, 0, NULL, 0);
5307 This->up_strided = NULL;
5308 return WINED3D_OK;
5311 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5312 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
5313 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
5315 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5316 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5318 /* Mark the state dirty until we have nicer tracking
5319 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5320 * that value.
5322 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5323 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5324 This->stateBlock->streamIsUP = TRUE;
5325 This->stateBlock->baseVertexIndex = 0;
5326 This->up_strided = DrawPrimStrideData;
5327 drawPrimitive(iface, vertex_count, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData, 0 /* minindex */);
5328 This->up_strided = NULL;
5329 return WINED3D_OK;
5332 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5333 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5334 * not callable by the app directly no parameter validation checks are needed here.
5336 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5337 WINED3DLOCKED_BOX src;
5338 WINED3DLOCKED_BOX dst;
5339 HRESULT hr;
5340 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5342 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5343 * dirtification to improve loading performance.
5345 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5346 if(FAILED(hr)) return hr;
5347 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5348 if(FAILED(hr)) {
5349 IWineD3DVolume_UnlockBox(pSourceVolume);
5350 return hr;
5353 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5355 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5356 if(FAILED(hr)) {
5357 IWineD3DVolume_UnlockBox(pSourceVolume);
5358 } else {
5359 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5361 return hr;
5364 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5365 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5366 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5367 HRESULT hr = WINED3D_OK;
5368 WINED3DRESOURCETYPE sourceType;
5369 WINED3DRESOURCETYPE destinationType;
5370 int i ,levels;
5372 /* TODO: think about moving the code into IWineD3DBaseTexture */
5374 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5376 /* verify that the source and destination textures aren't NULL */
5377 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5378 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5379 This, pSourceTexture, pDestinationTexture);
5380 hr = WINED3DERR_INVALIDCALL;
5383 if (pSourceTexture == pDestinationTexture) {
5384 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5385 This, pSourceTexture, pDestinationTexture);
5386 hr = WINED3DERR_INVALIDCALL;
5388 /* Verify that the source and destination textures are the same type */
5389 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5390 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5392 if (sourceType != destinationType) {
5393 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5394 This);
5395 hr = WINED3DERR_INVALIDCALL;
5398 /* check that both textures have the identical numbers of levels */
5399 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5400 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5401 hr = WINED3DERR_INVALIDCALL;
5404 if (WINED3D_OK == hr) {
5405 IWineD3DBaseTextureImpl *pDestImpl = (IWineD3DBaseTextureImpl *) pDestinationTexture;
5407 /* Make sure that the destination texture is loaded */
5408 pDestImpl->baseTexture.internal_preload(pDestinationTexture, SRGB_RGB);
5410 /* Update every surface level of the texture */
5411 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5413 switch (sourceType) {
5414 case WINED3DRTYPE_TEXTURE:
5416 IWineD3DSurface *srcSurface;
5417 IWineD3DSurface *destSurface;
5419 for (i = 0 ; i < levels ; ++i) {
5420 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5421 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5422 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5423 IWineD3DSurface_Release(srcSurface);
5424 IWineD3DSurface_Release(destSurface);
5425 if (WINED3D_OK != hr) {
5426 WARN("(%p) : Call to update surface failed\n", This);
5427 return hr;
5431 break;
5432 case WINED3DRTYPE_CUBETEXTURE:
5434 IWineD3DSurface *srcSurface;
5435 IWineD3DSurface *destSurface;
5436 WINED3DCUBEMAP_FACES faceType;
5438 for (i = 0 ; i < levels ; ++i) {
5439 /* Update each cube face */
5440 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5441 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5442 if (WINED3D_OK != hr) {
5443 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5444 } else {
5445 TRACE("Got srcSurface %p\n", srcSurface);
5447 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5448 if (WINED3D_OK != hr) {
5449 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5450 } else {
5451 TRACE("Got desrSurface %p\n", destSurface);
5453 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5454 IWineD3DSurface_Release(srcSurface);
5455 IWineD3DSurface_Release(destSurface);
5456 if (WINED3D_OK != hr) {
5457 WARN("(%p) : Call to update surface failed\n", This);
5458 return hr;
5463 break;
5465 case WINED3DRTYPE_VOLUMETEXTURE:
5467 IWineD3DVolume *srcVolume = NULL;
5468 IWineD3DVolume *destVolume = NULL;
5470 for (i = 0 ; i < levels ; ++i) {
5471 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5472 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5473 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5474 IWineD3DVolume_Release(srcVolume);
5475 IWineD3DVolume_Release(destVolume);
5476 if (WINED3D_OK != hr) {
5477 WARN("(%p) : Call to update volume failed\n", This);
5478 return hr;
5482 break;
5484 default:
5485 FIXME("(%p) : Unsupported source and destination type\n", This);
5486 hr = WINED3DERR_INVALIDCALL;
5490 return hr;
5493 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5494 IWineD3DSwapChain *swapChain;
5495 HRESULT hr;
5496 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5497 if(hr == WINED3D_OK) {
5498 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5499 IWineD3DSwapChain_Release(swapChain);
5501 return hr;
5504 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5505 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5506 IWineD3DBaseTextureImpl *texture;
5507 DWORD i;
5509 TRACE("(%p) : %p\n", This, pNumPasses);
5511 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5512 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5513 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5514 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5516 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5517 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5518 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5521 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5522 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5524 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5525 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5526 return E_FAIL;
5528 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5529 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5530 return E_FAIL;
5532 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5533 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5534 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5535 return E_FAIL;
5539 /* return a sensible default */
5540 *pNumPasses = 1;
5542 TRACE("returning D3D_OK\n");
5543 return WINED3D_OK;
5546 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5548 int i;
5550 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5551 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5552 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8
5553 || texture->resource.format_desc->format == WINED3DFMT_A8P8))
5555 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5560 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5561 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5562 int j;
5563 UINT NewSize;
5564 PALETTEENTRY **palettes;
5566 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5568 if (PaletteNumber >= MAX_PALETTES) {
5569 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5570 return WINED3DERR_INVALIDCALL;
5573 if (PaletteNumber >= This->NumberOfPalettes) {
5574 NewSize = This->NumberOfPalettes;
5575 do {
5576 NewSize *= 2;
5577 } while(PaletteNumber >= NewSize);
5578 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5579 if (!palettes) {
5580 ERR("Out of memory!\n");
5581 return E_OUTOFMEMORY;
5583 This->palettes = palettes;
5584 This->NumberOfPalettes = NewSize;
5587 if (!This->palettes[PaletteNumber]) {
5588 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5589 if (!This->palettes[PaletteNumber]) {
5590 ERR("Out of memory!\n");
5591 return E_OUTOFMEMORY;
5595 for (j = 0; j < 256; ++j) {
5596 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5597 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5598 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5599 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5601 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5602 TRACE("(%p) : returning\n", This);
5603 return WINED3D_OK;
5606 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5607 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5608 int j;
5609 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5610 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5611 /* What happens in such situation isn't documented; Native seems to silently abort
5612 on such conditions. Return Invalid Call. */
5613 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5614 return WINED3DERR_INVALIDCALL;
5616 for (j = 0; j < 256; ++j) {
5617 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5618 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5619 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5620 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5622 TRACE("(%p) : returning\n", This);
5623 return WINED3D_OK;
5626 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5627 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5628 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5629 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5630 (tested with reference rasterizer). Return Invalid Call. */
5631 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5632 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5633 return WINED3DERR_INVALIDCALL;
5635 /*TODO: stateblocks */
5636 if (This->currentPalette != PaletteNumber) {
5637 This->currentPalette = PaletteNumber;
5638 dirtify_p8_texture_samplers(This);
5640 TRACE("(%p) : returning\n", This);
5641 return WINED3D_OK;
5644 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5645 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5646 if (PaletteNumber == NULL) {
5647 WARN("(%p) : returning Invalid Call\n", This);
5648 return WINED3DERR_INVALIDCALL;
5650 /*TODO: stateblocks */
5651 *PaletteNumber = This->currentPalette;
5652 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5653 return WINED3D_OK;
5656 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5658 static BOOL warned;
5659 if (!warned)
5661 FIXME("(%p) : stub\n", This);
5662 warned = TRUE;
5665 This->softwareVertexProcessing = bSoftware;
5666 return WINED3D_OK;
5670 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5671 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5672 static BOOL warned;
5673 if (!warned)
5675 FIXME("(%p) : stub\n", This);
5676 warned = TRUE;
5678 return This->softwareVertexProcessing;
5682 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5683 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5684 IWineD3DSwapChain *swapChain;
5685 HRESULT hr;
5687 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5689 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5690 if(hr == WINED3D_OK){
5691 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5692 IWineD3DSwapChain_Release(swapChain);
5693 }else{
5694 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5696 return hr;
5700 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5701 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5702 static BOOL warned;
5703 if(nSegments != 0.0f) {
5704 if (!warned)
5706 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5707 warned = TRUE;
5710 return WINED3D_OK;
5713 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5714 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5715 static BOOL warned;
5716 if (!warned)
5718 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5719 warned = TRUE;
5721 return 0.0f;
5724 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5726 /** TODO: remove casts to IWineD3DSurfaceImpl
5727 * NOTE: move code to surface to accomplish this
5728 ****************************************/
5729 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5730 int srcWidth, srcHeight;
5731 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5732 WINED3DFORMAT destFormat, srcFormat;
5733 UINT destSize;
5734 int srcLeft, destLeft, destTop;
5735 WINED3DPOOL srcPool, destPool;
5736 int offset = 0;
5737 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5738 glDescriptor *glDescription = NULL;
5739 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
5740 GLenum dummy;
5741 int sampler;
5742 int bpp;
5743 CONVERT_TYPES convert = NO_CONVERSION;
5745 WINED3DSURFACE_DESC winedesc;
5747 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5749 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5750 srcSurfaceWidth = winedesc.width;
5751 srcSurfaceHeight = winedesc.height;
5752 srcPool = winedesc.pool;
5753 srcFormat = winedesc.format;
5755 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5756 destSurfaceWidth = winedesc.width;
5757 destSurfaceHeight = winedesc.height;
5758 destPool = winedesc.pool;
5759 destFormat = winedesc.format;
5760 destSize = winedesc.size;
5762 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5763 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5764 return WINED3DERR_INVALIDCALL;
5767 /* This call loads the opengl surface directly, instead of copying the surface to the
5768 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5769 * copy in sysmem and use regular surface loading.
5771 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5772 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5773 if(convert != NO_CONVERSION) {
5774 return IWineD3DSurface_BltFast(pDestinationSurface,
5775 pDestPoint ? pDestPoint->x : 0,
5776 pDestPoint ? pDestPoint->y : 0,
5777 pSourceSurface, pSourceRect, 0);
5780 if (destFormat == WINED3DFMT_UNKNOWN) {
5781 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5782 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5784 /* Get the update surface description */
5785 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5788 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5790 ENTER_GL();
5791 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5792 checkGLcall("glActiveTextureARB");
5793 LEAVE_GL();
5795 /* Make sure the surface is loaded and up to date */
5796 surface_internal_preload(pDestinationSurface, SRGB_RGB);
5797 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5799 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5801 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
5802 dst_format_desc = ((IWineD3DSurfaceImpl *)pDestinationSurface)->resource.format_desc;
5804 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5805 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5806 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5807 srcLeft = pSourceRect ? pSourceRect->left : 0;
5808 destLeft = pDestPoint ? pDestPoint->x : 0;
5809 destTop = pDestPoint ? pDestPoint->y : 0;
5812 /* This function doesn't support compressed textures
5813 the pitch is just bytesPerPixel * width */
5814 if(srcWidth != srcSurfaceWidth || srcLeft ){
5815 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
5816 offset += srcLeft * src_format_desc->byte_count;
5817 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5819 /* TODO DXT formats */
5821 if(pSourceRect != NULL && pSourceRect->top != 0){
5822 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
5824 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5825 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
5826 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5828 /* Sanity check */
5829 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5831 /* need to lock the surface to get the data */
5832 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5835 ENTER_GL();
5837 /* TODO: Cube and volume support */
5838 if(rowoffset != 0){
5839 /* not a whole row so we have to do it a line at a time */
5840 int j;
5842 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5843 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5845 for (j = destTop; j < (srcHeight + destTop); ++j)
5847 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, j,
5848 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
5849 data += rowoffset;
5852 } else { /* Full width, so just write out the whole texture */
5853 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5855 if (dst_format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
5857 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth)
5859 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across. */
5860 FIXME("Updating part of a compressed texture is not supported.\n");
5862 if (destFormat != srcFormat)
5864 FIXME("Updating mixed format compressed textures is not supported.\n");
5866 else
5868 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
5869 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
5872 else
5874 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
5875 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
5878 checkGLcall("glTexSubImage2D");
5880 LEAVE_GL();
5882 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5883 sampler = This->rev_tex_unit_map[0];
5884 if (sampler != -1) {
5885 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5888 return WINED3D_OK;
5891 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5893 struct WineD3DRectPatch *patch;
5894 GLenum old_primitive_type;
5895 unsigned int i;
5896 struct list *e;
5897 BOOL found;
5898 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5900 if(!(Handle || pRectPatchInfo)) {
5901 /* TODO: Write a test for the return value, thus the FIXME */
5902 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5903 return WINED3DERR_INVALIDCALL;
5906 if(Handle) {
5907 i = PATCHMAP_HASHFUNC(Handle);
5908 found = FALSE;
5909 LIST_FOR_EACH(e, &This->patches[i]) {
5910 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5911 if(patch->Handle == Handle) {
5912 found = TRUE;
5913 break;
5917 if(!found) {
5918 TRACE("Patch does not exist. Creating a new one\n");
5919 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5920 patch->Handle = Handle;
5921 list_add_head(&This->patches[i], &patch->entry);
5922 } else {
5923 TRACE("Found existing patch %p\n", patch);
5925 } else {
5926 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5927 * attributes we have to tesselate, read back, and draw. This needs a patch
5928 * management structure instance. Create one.
5930 * A possible improvement is to check if a vertex shader is used, and if not directly
5931 * draw the patch.
5933 FIXME("Drawing an uncached patch. This is slow\n");
5934 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5937 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5938 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5939 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5940 HRESULT hr;
5941 TRACE("Tesselation density or patch info changed, retesselating\n");
5943 if(pRectPatchInfo) {
5944 patch->RectPatchInfo = *pRectPatchInfo;
5946 patch->numSegs[0] = pNumSegs[0];
5947 patch->numSegs[1] = pNumSegs[1];
5948 patch->numSegs[2] = pNumSegs[2];
5949 patch->numSegs[3] = pNumSegs[3];
5951 hr = tesselate_rectpatch(This, patch);
5952 if(FAILED(hr)) {
5953 WARN("Patch tesselation failed\n");
5955 /* Do not release the handle to store the params of the patch */
5956 if(!Handle) {
5957 HeapFree(GetProcessHeap(), 0, patch);
5959 return hr;
5963 This->currentPatch = patch;
5964 old_primitive_type = This->stateBlock->gl_primitive_type;
5965 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5966 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5967 This->stateBlock->gl_primitive_type = old_primitive_type;
5968 This->currentPatch = NULL;
5970 /* Destroy uncached patches */
5971 if(!Handle) {
5972 HeapFree(GetProcessHeap(), 0, patch->mem);
5973 HeapFree(GetProcessHeap(), 0, patch);
5975 return WINED3D_OK;
5978 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5979 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5980 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5981 FIXME("(%p) : Stub\n", This);
5982 return WINED3D_OK;
5985 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5986 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5987 int i;
5988 struct WineD3DRectPatch *patch;
5989 struct list *e;
5990 TRACE("(%p) Handle(%d)\n", This, Handle);
5992 i = PATCHMAP_HASHFUNC(Handle);
5993 LIST_FOR_EACH(e, &This->patches[i]) {
5994 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5995 if(patch->Handle == Handle) {
5996 TRACE("Deleting patch %p\n", patch);
5997 list_remove(&patch->entry);
5998 HeapFree(GetProcessHeap(), 0, patch->mem);
5999 HeapFree(GetProcessHeap(), 0, patch);
6000 return WINED3D_OK;
6004 /* TODO: Write a test for the return value */
6005 FIXME("Attempt to destroy nonexistent patch\n");
6006 return WINED3DERR_INVALIDCALL;
6009 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6010 HRESULT hr;
6011 IWineD3DSwapChain *swapchain;
6013 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6014 if (SUCCEEDED(hr)) {
6015 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6016 return swapchain;
6019 return NULL;
6022 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
6023 const WINED3DRECT *rect, const float color[4])
6025 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6026 IWineD3DSwapChain *swapchain;
6028 swapchain = get_swapchain(surface);
6029 if (swapchain) {
6030 GLenum buffer;
6032 TRACE("Surface %p is onscreen\n", surface);
6034 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6035 ENTER_GL();
6036 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6037 buffer = surface_get_gl_buffer(surface, swapchain);
6038 glDrawBuffer(buffer);
6039 checkGLcall("glDrawBuffer()");
6040 } else {
6041 TRACE("Surface %p is offscreen\n", surface);
6043 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6044 ENTER_GL();
6045 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6046 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6047 context_attach_depth_stencil_fbo(This, GL_FRAMEBUFFER_EXT, NULL, FALSE);
6050 if (rect) {
6051 glEnable(GL_SCISSOR_TEST);
6052 if(!swapchain) {
6053 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6054 } else {
6055 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6056 rect->x2 - rect->x1, rect->y2 - rect->y1);
6058 checkGLcall("glScissor");
6059 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6060 } else {
6061 glDisable(GL_SCISSOR_TEST);
6063 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6065 glDisable(GL_BLEND);
6066 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6068 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6069 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6071 glClearColor(color[0], color[1], color[2], color[3]);
6072 glClear(GL_COLOR_BUFFER_BIT);
6073 checkGLcall("glClear");
6075 if (This->activeContext->current_fbo) {
6076 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6077 } else {
6078 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6079 checkGLcall("glBindFramebuffer()");
6082 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6083 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6084 glDrawBuffer(GL_BACK);
6085 checkGLcall("glDrawBuffer()");
6088 LEAVE_GL();
6091 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6092 unsigned int r, g, b, a;
6093 DWORD ret;
6095 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6096 destfmt == WINED3DFMT_R8G8B8)
6097 return color;
6099 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6101 a = (color & 0xff000000) >> 24;
6102 r = (color & 0x00ff0000) >> 16;
6103 g = (color & 0x0000ff00) >> 8;
6104 b = (color & 0x000000ff) >> 0;
6106 switch(destfmt)
6108 case WINED3DFMT_R5G6B5:
6109 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6110 r = (r * 32) / 256;
6111 g = (g * 64) / 256;
6112 b = (b * 32) / 256;
6113 ret = r << 11;
6114 ret |= g << 5;
6115 ret |= b;
6116 TRACE("Returning %08x\n", ret);
6117 return ret;
6119 case WINED3DFMT_X1R5G5B5:
6120 case WINED3DFMT_A1R5G5B5:
6121 a = (a * 2) / 256;
6122 r = (r * 32) / 256;
6123 g = (g * 32) / 256;
6124 b = (b * 32) / 256;
6125 ret = a << 15;
6126 ret |= r << 10;
6127 ret |= g << 5;
6128 ret |= b << 0;
6129 TRACE("Returning %08x\n", ret);
6130 return ret;
6132 case WINED3DFMT_A8_UNORM:
6133 TRACE("Returning %08x\n", a);
6134 return a;
6136 case WINED3DFMT_X4R4G4B4:
6137 case WINED3DFMT_A4R4G4B4:
6138 a = (a * 16) / 256;
6139 r = (r * 16) / 256;
6140 g = (g * 16) / 256;
6141 b = (b * 16) / 256;
6142 ret = a << 12;
6143 ret |= r << 8;
6144 ret |= g << 4;
6145 ret |= b << 0;
6146 TRACE("Returning %08x\n", ret);
6147 return ret;
6149 case WINED3DFMT_R3G3B2:
6150 r = (r * 8) / 256;
6151 g = (g * 8) / 256;
6152 b = (b * 4) / 256;
6153 ret = r << 5;
6154 ret |= g << 2;
6155 ret |= b << 0;
6156 TRACE("Returning %08x\n", ret);
6157 return ret;
6159 case WINED3DFMT_X8B8G8R8:
6160 case WINED3DFMT_R8G8B8A8_UNORM:
6161 ret = a << 24;
6162 ret |= b << 16;
6163 ret |= g << 8;
6164 ret |= r << 0;
6165 TRACE("Returning %08x\n", ret);
6166 return ret;
6168 case WINED3DFMT_A2R10G10B10:
6169 a = (a * 4) / 256;
6170 r = (r * 1024) / 256;
6171 g = (g * 1024) / 256;
6172 b = (b * 1024) / 256;
6173 ret = a << 30;
6174 ret |= r << 20;
6175 ret |= g << 10;
6176 ret |= b << 0;
6177 TRACE("Returning %08x\n", ret);
6178 return ret;
6180 case WINED3DFMT_R10G10B10A2_UNORM:
6181 a = (a * 4) / 256;
6182 r = (r * 1024) / 256;
6183 g = (g * 1024) / 256;
6184 b = (b * 1024) / 256;
6185 ret = a << 30;
6186 ret |= b << 20;
6187 ret |= g << 10;
6188 ret |= r << 0;
6189 TRACE("Returning %08x\n", ret);
6190 return ret;
6192 default:
6193 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6194 return 0;
6198 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6199 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6200 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6201 WINEDDBLTFX BltFx;
6202 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6204 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6205 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6206 return WINED3DERR_INVALIDCALL;
6209 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6210 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
6211 color_fill_fbo(iface, pSurface, pRect, c);
6212 return WINED3D_OK;
6213 } else {
6214 /* Just forward this to the DirectDraw blitting engine */
6215 memset(&BltFx, 0, sizeof(BltFx));
6216 BltFx.dwSize = sizeof(BltFx);
6217 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
6218 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6219 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6223 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
6224 IWineD3DRendertargetView *rendertarget_view, const float color[4])
6226 IWineD3DResource *resource;
6227 IWineD3DSurface *surface;
6228 HRESULT hr;
6230 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
6231 if (FAILED(hr))
6233 ERR("Failed to get resource, hr %#x\n", hr);
6234 return;
6237 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
6239 FIXME("Only supported on surface resources\n");
6240 IWineD3DResource_Release(resource);
6241 return;
6244 surface = (IWineD3DSurface *)resource;
6246 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6248 color_fill_fbo(iface, surface, NULL, color);
6250 else
6252 WINEDDBLTFX BltFx;
6253 WINED3DCOLOR c;
6255 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
6257 c = ((DWORD)(color[2] * 255.0));
6258 c |= ((DWORD)(color[1] * 255.0)) << 8;
6259 c |= ((DWORD)(color[0] * 255.0)) << 16;
6260 c |= ((DWORD)(color[3] * 255.0)) << 24;
6262 /* Just forward this to the DirectDraw blitting engine */
6263 memset(&BltFx, 0, sizeof(BltFx));
6264 BltFx.dwSize = sizeof(BltFx);
6265 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
6266 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6267 if (FAILED(hr))
6269 ERR("Blt failed, hr %#x\n", hr);
6273 IWineD3DResource_Release(resource);
6276 /* rendertarget and depth stencil functions */
6277 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6278 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6280 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6281 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6282 return WINED3DERR_INVALIDCALL;
6285 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6286 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6287 /* Note inc ref on returned surface */
6288 if(*ppRenderTarget != NULL)
6289 IWineD3DSurface_AddRef(*ppRenderTarget);
6290 return WINED3D_OK;
6293 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6294 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6295 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6296 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6297 IWineD3DSwapChainImpl *Swapchain;
6298 HRESULT hr;
6300 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6302 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6303 if(hr != WINED3D_OK) {
6304 ERR("Can't get the swapchain\n");
6305 return hr;
6308 /* Make sure to release the swapchain */
6309 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6311 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6312 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6313 return WINED3DERR_INVALIDCALL;
6315 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6316 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6317 return WINED3DERR_INVALIDCALL;
6320 if(Swapchain->frontBuffer != Front) {
6321 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6323 if(Swapchain->frontBuffer)
6325 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6326 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
6328 Swapchain->frontBuffer = Front;
6330 if(Swapchain->frontBuffer) {
6331 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6332 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
6336 if(Back && !Swapchain->backBuffer) {
6337 /* We need memory for the back buffer array - only one back buffer this way */
6338 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6339 if(!Swapchain->backBuffer) {
6340 ERR("Out of memory\n");
6341 return E_OUTOFMEMORY;
6345 if(Swapchain->backBuffer[0] != Back) {
6346 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6348 /* What to do about the context here in the case of multithreading? Not sure.
6349 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6351 ENTER_GL();
6352 if(!Swapchain->backBuffer[0]) {
6353 /* GL was told to draw to the front buffer at creation,
6354 * undo that
6356 glDrawBuffer(GL_BACK);
6357 checkGLcall("glDrawBuffer(GL_BACK)");
6358 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6359 Swapchain->presentParms.BackBufferCount = 1;
6360 } else if (!Back) {
6361 /* That makes problems - disable for now */
6362 /* glDrawBuffer(GL_FRONT); */
6363 checkGLcall("glDrawBuffer(GL_FRONT)");
6364 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6365 Swapchain->presentParms.BackBufferCount = 0;
6367 LEAVE_GL();
6369 if(Swapchain->backBuffer[0])
6371 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6372 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
6374 Swapchain->backBuffer[0] = Back;
6376 if(Swapchain->backBuffer[0]) {
6377 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6378 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
6379 } else {
6380 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6381 Swapchain->backBuffer = NULL;
6386 return WINED3D_OK;
6389 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6391 *ppZStencilSurface = This->stencilBufferTarget;
6392 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6394 if(*ppZStencilSurface != NULL) {
6395 /* Note inc ref on returned surface */
6396 IWineD3DSurface_AddRef(*ppZStencilSurface);
6397 return WINED3D_OK;
6398 } else {
6399 return WINED3DERR_NOTFOUND;
6403 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6404 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6406 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6407 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6408 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6409 GLenum gl_filter;
6410 POINT offset = {0, 0};
6412 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6413 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6414 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6415 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6417 switch (filter) {
6418 case WINED3DTEXF_LINEAR:
6419 gl_filter = GL_LINEAR;
6420 break;
6422 default:
6423 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6424 case WINED3DTEXF_NONE:
6425 case WINED3DTEXF_POINT:
6426 gl_filter = GL_NEAREST;
6427 break;
6430 /* Attach src surface to src fbo */
6431 src_swapchain = get_swapchain(src_surface);
6432 dst_swapchain = get_swapchain(dst_surface);
6434 if (src_swapchain) ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6435 else if (dst_swapchain) ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6436 else ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6438 if (src_swapchain) {
6439 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6441 TRACE("Source surface %p is onscreen\n", src_surface);
6442 /* Make sure the drawable is up to date. In the offscreen case
6443 * attach_surface_fbo() implicitly takes care of this. */
6444 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6446 if(buffer == GL_FRONT) {
6447 RECT windowsize;
6448 UINT h;
6449 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6450 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6451 h = windowsize.bottom - windowsize.top;
6452 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6453 src_rect->y1 = offset.y + h - src_rect->y1;
6454 src_rect->y2 = offset.y + h - src_rect->y2;
6455 } else {
6456 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6457 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6460 ENTER_GL();
6461 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6462 glReadBuffer(buffer);
6463 checkGLcall("glReadBuffer()");
6464 } else {
6465 TRACE("Source surface %p is offscreen\n", src_surface);
6466 ENTER_GL();
6467 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6468 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6469 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6470 checkGLcall("glReadBuffer()");
6471 context_attach_depth_stencil_fbo(This, GL_READ_FRAMEBUFFER_EXT, NULL, FALSE);
6473 LEAVE_GL();
6475 /* Attach dst surface to dst fbo */
6476 if (dst_swapchain) {
6477 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6479 TRACE("Destination surface %p is onscreen\n", dst_surface);
6480 /* Make sure the drawable is up to date. In the offscreen case
6481 * attach_surface_fbo() implicitly takes care of this. */
6482 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6484 if(buffer == GL_FRONT) {
6485 RECT windowsize;
6486 UINT h;
6487 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6488 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6489 h = windowsize.bottom - windowsize.top;
6490 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6491 dst_rect->y1 = offset.y + h - dst_rect->y1;
6492 dst_rect->y2 = offset.y + h - dst_rect->y2;
6493 } else {
6494 /* Screen coords = window coords, surface height = window height */
6495 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6496 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6499 ENTER_GL();
6500 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6501 glDrawBuffer(buffer);
6502 checkGLcall("glDrawBuffer()");
6503 } else {
6504 TRACE("Destination surface %p is offscreen\n", dst_surface);
6506 ENTER_GL();
6507 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6508 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6509 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6510 checkGLcall("glDrawBuffer()");
6511 context_attach_depth_stencil_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, NULL, FALSE);
6513 glDisable(GL_SCISSOR_TEST);
6514 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6516 if (flip) {
6517 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6518 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6519 checkGLcall("glBlitFramebuffer()");
6520 } else {
6521 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6522 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6523 checkGLcall("glBlitFramebuffer()");
6526 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6528 if (This->activeContext->current_fbo) {
6529 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6530 } else {
6531 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6532 checkGLcall("glBindFramebuffer()");
6535 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6536 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6537 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6538 glDrawBuffer(GL_BACK);
6539 checkGLcall("glDrawBuffer()");
6541 LEAVE_GL();
6544 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6545 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6546 WINED3DVIEWPORT viewport;
6548 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6550 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6551 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6552 This, RenderTargetIndex, GL_LIMITS(buffers));
6553 return WINED3DERR_INVALIDCALL;
6556 /* MSDN says that null disables the render target
6557 but a device must always be associated with a render target
6558 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6560 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6561 FIXME("Trying to set render target 0 to NULL\n");
6562 return WINED3DERR_INVALIDCALL;
6564 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6565 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);
6566 return WINED3DERR_INVALIDCALL;
6569 /* If we are trying to set what we already have, don't bother */
6570 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6571 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6572 return WINED3D_OK;
6574 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6575 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6576 This->render_targets[RenderTargetIndex] = pRenderTarget;
6578 /* Render target 0 is special */
6579 if(RenderTargetIndex == 0) {
6580 /* Finally, reset the viewport as the MSDN states. */
6581 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6582 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6583 viewport.X = 0;
6584 viewport.Y = 0;
6585 viewport.MaxZ = 1.0f;
6586 viewport.MinZ = 0.0f;
6587 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6588 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6589 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6591 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6593 return WINED3D_OK;
6596 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6597 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6598 HRESULT hr = WINED3D_OK;
6599 IWineD3DSurface *tmp;
6601 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6603 if (pNewZStencil == This->stencilBufferTarget) {
6604 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6605 } else {
6606 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6607 * depending on the renter target implementation being used.
6608 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6609 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6610 * stencil buffer and incur an extra memory overhead
6611 ******************************************************/
6613 if (This->stencilBufferTarget) {
6614 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6615 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6616 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6617 } else {
6618 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6619 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6620 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6624 tmp = This->stencilBufferTarget;
6625 This->stencilBufferTarget = pNewZStencil;
6626 /* should we be calling the parent or the wined3d surface? */
6627 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6628 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6629 hr = WINED3D_OK;
6631 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6632 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6633 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6634 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6635 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6639 return hr;
6642 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6643 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6644 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6645 /* TODO: the use of Impl is deprecated. */
6646 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6647 WINED3DLOCKED_RECT lockedRect;
6649 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6651 /* some basic validation checks */
6652 if(This->cursorTexture) {
6653 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6654 ENTER_GL();
6655 glDeleteTextures(1, &This->cursorTexture);
6656 LEAVE_GL();
6657 This->cursorTexture = 0;
6660 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6661 This->haveHardwareCursor = TRUE;
6662 else
6663 This->haveHardwareCursor = FALSE;
6665 if(pCursorBitmap) {
6666 WINED3DLOCKED_RECT rect;
6668 /* MSDN: Cursor must be A8R8G8B8 */
6669 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format_desc->format)
6671 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6672 return WINED3DERR_INVALIDCALL;
6675 /* MSDN: Cursor must be smaller than the display mode */
6676 if(pSur->currentDesc.Width > This->ddraw_width ||
6677 pSur->currentDesc.Height > This->ddraw_height) {
6678 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);
6679 return WINED3DERR_INVALIDCALL;
6682 if (!This->haveHardwareCursor) {
6683 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6685 /* Do not store the surface's pointer because the application may
6686 * release it after setting the cursor image. Windows doesn't
6687 * addref the set surface, so we can't do this either without
6688 * creating circular refcount dependencies. Copy out the gl texture
6689 * instead.
6691 This->cursorWidth = pSur->currentDesc.Width;
6692 This->cursorHeight = pSur->currentDesc.Height;
6693 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6695 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION);
6696 char *mem, *bits = rect.pBits;
6697 GLint intfmt = glDesc->glInternal;
6698 GLint format = glDesc->glFormat;
6699 GLint type = glDesc->glType;
6700 INT height = This->cursorHeight;
6701 INT width = This->cursorWidth;
6702 INT bpp = glDesc->byte_count;
6703 INT i, sampler;
6705 /* Reformat the texture memory (pitch and width can be
6706 * different) */
6707 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6708 for(i = 0; i < height; i++)
6709 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6710 IWineD3DSurface_UnlockRect(pCursorBitmap);
6711 ENTER_GL();
6713 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6714 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6715 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6718 /* Make sure that a proper texture unit is selected */
6719 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6720 checkGLcall("glActiveTextureARB");
6721 sampler = This->rev_tex_unit_map[0];
6722 if (sampler != -1) {
6723 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6725 /* Create a new cursor texture */
6726 glGenTextures(1, &This->cursorTexture);
6727 checkGLcall("glGenTextures");
6728 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6729 checkGLcall("glBindTexture");
6730 /* Copy the bitmap memory into the cursor texture */
6731 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6732 HeapFree(GetProcessHeap(), 0, mem);
6733 checkGLcall("glTexImage2D");
6735 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6736 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6737 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6740 LEAVE_GL();
6742 else
6744 FIXME("A cursor texture was not returned.\n");
6745 This->cursorTexture = 0;
6748 else
6750 /* Draw a hardware cursor */
6751 ICONINFO cursorInfo;
6752 HCURSOR cursor;
6753 /* Create and clear maskBits because it is not needed for
6754 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6755 * chunks. */
6756 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6757 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6758 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6759 WINED3DLOCK_NO_DIRTY_UPDATE |
6760 WINED3DLOCK_READONLY
6762 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6763 pSur->currentDesc.Height);
6765 cursorInfo.fIcon = FALSE;
6766 cursorInfo.xHotspot = XHotSpot;
6767 cursorInfo.yHotspot = YHotSpot;
6768 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6769 pSur->currentDesc.Height, 1,
6770 1, &maskBits);
6771 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6772 pSur->currentDesc.Height, 1,
6773 32, lockedRect.pBits);
6774 IWineD3DSurface_UnlockRect(pCursorBitmap);
6775 /* Create our cursor and clean up. */
6776 cursor = CreateIconIndirect(&cursorInfo);
6777 SetCursor(cursor);
6778 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6779 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6780 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6781 This->hardwareCursor = cursor;
6782 HeapFree(GetProcessHeap(), 0, maskBits);
6786 This->xHotSpot = XHotSpot;
6787 This->yHotSpot = YHotSpot;
6788 return WINED3D_OK;
6791 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6792 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6793 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6795 This->xScreenSpace = XScreenSpace;
6796 This->yScreenSpace = YScreenSpace;
6798 return;
6802 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6803 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6804 BOOL oldVisible = This->bCursorVisible;
6805 POINT pt;
6807 TRACE("(%p) : visible(%d)\n", This, bShow);
6810 * When ShowCursor is first called it should make the cursor appear at the OS's last
6811 * known cursor position. Because of this, some applications just repetitively call
6812 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6814 GetCursorPos(&pt);
6815 This->xScreenSpace = pt.x;
6816 This->yScreenSpace = pt.y;
6818 if (This->haveHardwareCursor) {
6819 This->bCursorVisible = bShow;
6820 if (bShow)
6821 SetCursor(This->hardwareCursor);
6822 else
6823 SetCursor(NULL);
6825 else
6827 if (This->cursorTexture)
6828 This->bCursorVisible = bShow;
6831 return oldVisible;
6834 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6835 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6836 IWineD3DResourceImpl *resource;
6837 TRACE("(%p) : state (%u)\n", This, This->state);
6839 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6840 switch (This->state) {
6841 case WINED3D_OK:
6842 return WINED3D_OK;
6843 case WINED3DERR_DEVICELOST:
6845 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6846 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6847 return WINED3DERR_DEVICENOTRESET;
6849 return WINED3DERR_DEVICELOST;
6851 case WINED3DERR_DRIVERINTERNALERROR:
6852 return WINED3DERR_DRIVERINTERNALERROR;
6855 /* Unknown state */
6856 return WINED3DERR_DRIVERINTERNALERROR;
6860 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6861 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6862 /** FIXME: Resource tracking needs to be done,
6863 * The closes we can do to this is set the priorities of all managed textures low
6864 * and then reset them.
6865 ***********************************************************/
6866 FIXME("(%p) : stub\n", This);
6867 return WINED3D_OK;
6870 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6872 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6874 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6875 if(surface->Flags & SFLAG_DIBSECTION) {
6876 /* Release the DC */
6877 SelectObject(surface->hDC, surface->dib.holdbitmap);
6878 DeleteDC(surface->hDC);
6879 /* Release the DIB section */
6880 DeleteObject(surface->dib.DIBsection);
6881 surface->dib.bitmap_data = NULL;
6882 surface->resource.allocatedMemory = NULL;
6883 surface->Flags &= ~SFLAG_DIBSECTION;
6885 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6886 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6887 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
6888 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
6889 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6890 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6891 } else {
6892 surface->pow2Width = surface->pow2Height = 1;
6893 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6894 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6896 surface->glRect.left = 0;
6897 surface->glRect.top = 0;
6898 surface->glRect.right = surface->pow2Width;
6899 surface->glRect.bottom = surface->pow2Height;
6901 if(surface->glDescription.textureName) {
6902 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6903 ENTER_GL();
6904 glDeleteTextures(1, &surface->glDescription.textureName);
6905 LEAVE_GL();
6906 surface->glDescription.textureName = 0;
6907 surface->Flags &= ~SFLAG_CLIENT;
6909 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6910 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6911 surface->Flags |= SFLAG_NONPOW2;
6912 } else {
6913 surface->Flags &= ~SFLAG_NONPOW2;
6915 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6916 surface->resource.allocatedMemory = NULL;
6917 surface->resource.heapMemory = NULL;
6918 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6919 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
6920 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
6921 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
6922 } else {
6923 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
6927 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6928 TRACE("Unloading resource %p\n", resource);
6929 IWineD3DResource_UnLoad(resource);
6930 IWineD3DResource_Release(resource);
6931 return S_OK;
6934 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6936 UINT i, count;
6937 WINED3DDISPLAYMODE m;
6938 HRESULT hr;
6940 /* All Windowed modes are supported, as is leaving the current mode */
6941 if(pp->Windowed) return TRUE;
6942 if(!pp->BackBufferWidth) return TRUE;
6943 if(!pp->BackBufferHeight) return TRUE;
6945 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
6946 for(i = 0; i < count; i++) {
6947 memset(&m, 0, sizeof(m));
6948 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
6949 if(FAILED(hr)) {
6950 ERR("EnumAdapterModes failed\n");
6952 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6953 /* Mode found, it is supported */
6954 return TRUE;
6957 /* Mode not found -> not supported */
6958 return FALSE;
6961 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6962 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6963 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6964 UINT i;
6965 IWineD3DBaseShaderImpl *shader;
6967 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6968 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6969 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6972 ENTER_GL();
6973 if(This->depth_blt_texture) {
6974 glDeleteTextures(1, &This->depth_blt_texture);
6975 This->depth_blt_texture = 0;
6977 if (This->depth_blt_rb) {
6978 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
6979 This->depth_blt_rb = 0;
6980 This->depth_blt_rb_w = 0;
6981 This->depth_blt_rb_h = 0;
6983 LEAVE_GL();
6985 This->blitter->free_private(iface);
6986 This->frag_pipe->free_private(iface);
6987 This->shader_backend->shader_free_private(iface);
6989 ENTER_GL();
6990 for (i = 0; i < GL_LIMITS(textures); i++) {
6991 /* Textures are recreated below */
6992 glDeleteTextures(1, &This->dummyTextureName[i]);
6993 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
6994 This->dummyTextureName[i] = 0;
6996 LEAVE_GL();
6998 while(This->numContexts) {
6999 DestroyContext(This, This->contexts[0]);
7001 This->activeContext = NULL;
7002 HeapFree(GetProcessHeap(), 0, swapchain->context);
7003 swapchain->context = NULL;
7004 swapchain->num_contexts = 0;
7007 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7009 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7010 HRESULT hr;
7011 IWineD3DSurfaceImpl *target;
7013 /* Recreate the primary swapchain's context */
7014 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7015 if(swapchain->backBuffer) {
7016 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7017 } else {
7018 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7020 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7021 &swapchain->presentParms);
7022 swapchain->num_contexts = 1;
7023 This->activeContext = swapchain->context[0];
7025 create_dummy_textures(This);
7027 hr = This->shader_backend->shader_alloc_private(iface);
7028 if(FAILED(hr)) {
7029 ERR("Failed to recreate shader private data\n");
7030 goto err_out;
7032 hr = This->frag_pipe->alloc_private(iface);
7033 if(FAILED(hr)) {
7034 TRACE("Fragment pipeline private data couldn't be allocated\n");
7035 goto err_out;
7037 hr = This->blitter->alloc_private(iface);
7038 if(FAILED(hr)) {
7039 TRACE("Blitter private data couldn't be allocated\n");
7040 goto err_out;
7043 return WINED3D_OK;
7045 err_out:
7046 This->blitter->free_private(iface);
7047 This->frag_pipe->free_private(iface);
7048 This->shader_backend->shader_free_private(iface);
7049 return hr;
7052 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7053 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7054 IWineD3DSwapChainImpl *swapchain;
7055 HRESULT hr;
7056 BOOL DisplayModeChanged = FALSE;
7057 WINED3DDISPLAYMODE mode;
7058 TRACE("(%p)\n", This);
7060 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7061 if(FAILED(hr)) {
7062 ERR("Failed to get the first implicit swapchain\n");
7063 return hr;
7066 if(!is_display_mode_supported(This, pPresentationParameters)) {
7067 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7068 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7069 pPresentationParameters->BackBufferHeight);
7070 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
7071 return WINED3DERR_INVALIDCALL;
7074 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7075 * on an existing gl context, so there's no real need for recreation.
7077 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7079 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7081 TRACE("New params:\n");
7082 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7083 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7084 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7085 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7086 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7087 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7088 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7089 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7090 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7091 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7092 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7093 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7094 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7096 /* No special treatment of these parameters. Just store them */
7097 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7098 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7099 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7100 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7102 /* What to do about these? */
7103 if(pPresentationParameters->BackBufferCount != 0 &&
7104 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7105 ERR("Cannot change the back buffer count yet\n");
7107 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7108 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7109 ERR("Cannot change the back buffer format yet\n");
7111 if(pPresentationParameters->hDeviceWindow != NULL &&
7112 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7113 ERR("Cannot change the device window yet\n");
7115 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7116 HRESULT hrc;
7118 TRACE("Creating the depth stencil buffer\n");
7120 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
7121 This->parent,
7122 pPresentationParameters->BackBufferWidth,
7123 pPresentationParameters->BackBufferHeight,
7124 pPresentationParameters->AutoDepthStencilFormat,
7125 pPresentationParameters->MultiSampleType,
7126 pPresentationParameters->MultiSampleQuality,
7127 FALSE,
7128 &This->auto_depth_stencil_buffer);
7130 if (FAILED(hrc)) {
7131 ERR("Failed to create the depth stencil buffer\n");
7132 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7133 return WINED3DERR_INVALIDCALL;
7137 /* Reset the depth stencil */
7138 if (pPresentationParameters->EnableAutoDepthStencil)
7139 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7140 else
7141 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7143 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7145 if(pPresentationParameters->Windowed) {
7146 mode.Width = swapchain->orig_width;
7147 mode.Height = swapchain->orig_height;
7148 mode.RefreshRate = 0;
7149 mode.Format = swapchain->presentParms.BackBufferFormat;
7150 } else {
7151 mode.Width = pPresentationParameters->BackBufferWidth;
7152 mode.Height = pPresentationParameters->BackBufferHeight;
7153 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7154 mode.Format = swapchain->presentParms.BackBufferFormat;
7157 /* Should Width == 800 && Height == 0 set 800x600? */
7158 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7159 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7160 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7162 UINT i;
7164 if(!pPresentationParameters->Windowed) {
7165 DisplayModeChanged = TRUE;
7167 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7168 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7170 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7171 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7172 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7174 if(This->auto_depth_stencil_buffer) {
7175 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7179 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7180 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7181 DisplayModeChanged) {
7183 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7185 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7186 if(swapchain->presentParms.Windowed) {
7187 /* switch from windowed to fs */
7188 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7189 pPresentationParameters->BackBufferWidth,
7190 pPresentationParameters->BackBufferHeight);
7191 } else {
7192 /* Fullscreen -> fullscreen mode change */
7193 MoveWindow(swapchain->win_handle, 0, 0,
7194 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7195 TRUE);
7197 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7198 /* Fullscreen -> windowed switch */
7199 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7201 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7202 } else if(!pPresentationParameters->Windowed) {
7203 DWORD style = This->style, exStyle = This->exStyle;
7204 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7205 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7206 * Reset to clear up their mess. Guild Wars also loses the device during that.
7208 This->style = 0;
7209 This->exStyle = 0;
7210 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7211 pPresentationParameters->BackBufferWidth,
7212 pPresentationParameters->BackBufferHeight);
7213 This->style = style;
7214 This->exStyle = exStyle;
7217 TRACE("Resetting stateblock\n");
7218 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
7219 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
7221 /* Note: No parent needed for initial internal stateblock */
7222 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
7223 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7224 else TRACE("Created stateblock %p\n", This->stateBlock);
7225 This->updateStateBlock = This->stateBlock;
7226 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
7228 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7229 if(FAILED(hr)) {
7230 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7233 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7234 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7236 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7237 * first use
7239 return hr;
7242 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7243 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7244 /** FIXME: always true at the moment **/
7245 if(!bEnableDialogs) {
7246 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7248 return WINED3D_OK;
7252 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7253 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7254 TRACE("(%p) : pParameters %p\n", This, pParameters);
7256 *pParameters = This->createParms;
7257 return WINED3D_OK;
7260 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7261 IWineD3DSwapChain *swapchain;
7263 TRACE("Relaying to swapchain\n");
7265 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7266 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7267 IWineD3DSwapChain_Release(swapchain);
7269 return;
7272 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7273 IWineD3DSwapChain *swapchain;
7275 TRACE("Relaying to swapchain\n");
7277 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7278 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7279 IWineD3DSwapChain_Release(swapchain);
7281 return;
7285 /** ********************************************************
7286 * Notification functions
7287 ** ********************************************************/
7288 /** This function must be called in the release of a resource when ref == 0,
7289 * the contents of resource must still be correct,
7290 * any handles to other resource held by the caller must be closed
7291 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7292 *****************************************************/
7293 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7295 TRACE("(%p) : Adding resource %p\n", This, resource);
7297 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7300 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7302 TRACE("(%p) : Removing resource %p\n", This, resource);
7304 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7307 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7309 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7310 int counter;
7312 TRACE("(%p) : resource %p\n", This, resource);
7314 context_resource_released((IWineD3DDevice *)This, resource, type);
7316 switch (type) {
7317 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7318 case WINED3DRTYPE_SURFACE: {
7319 unsigned int i;
7321 /* Cleanup any FBO attachments if d3d is enabled */
7322 if(This->d3d_initialized) {
7323 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7324 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7326 TRACE("Last active render target destroyed\n");
7327 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7328 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7329 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7330 * and the lastActiveRenderTarget member shouldn't matter
7332 if(swapchain) {
7333 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7334 TRACE("Activating primary back buffer\n");
7335 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7336 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7337 /* Single buffering environment */
7338 TRACE("Activating primary front buffer\n");
7339 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7340 } else {
7341 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7342 /* Implicit render target destroyed, that means the device is being destroyed
7343 * whatever we set here, it shouldn't matter
7345 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7347 } else {
7348 /* May happen during ddraw uninitialization */
7349 TRACE("Render target set, but swapchain does not exist!\n");
7350 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7354 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7355 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7356 This->render_targets[i] = NULL;
7359 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7360 This->stencilBufferTarget = NULL;
7364 break;
7366 case WINED3DRTYPE_TEXTURE:
7367 case WINED3DRTYPE_CUBETEXTURE:
7368 case WINED3DRTYPE_VOLUMETEXTURE:
7369 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7370 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7371 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7372 This->stateBlock->textures[counter] = NULL;
7374 if (This->updateStateBlock != This->stateBlock ){
7375 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7376 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7377 This->updateStateBlock->textures[counter] = NULL;
7381 break;
7382 case WINED3DRTYPE_VOLUME:
7383 /* TODO: nothing really? */
7384 break;
7385 case WINED3DRTYPE_BUFFER:
7387 int streamNumber;
7388 TRACE("Cleaning up stream pointers\n");
7390 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7391 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7392 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7394 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7395 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7396 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7397 This->updateStateBlock->streamSource[streamNumber] = 0;
7398 /* Set changed flag? */
7401 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) */
7402 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7403 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7404 This->stateBlock->streamSource[streamNumber] = 0;
7409 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7410 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7411 This->updateStateBlock->pIndexData = NULL;
7414 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7415 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7416 This->stateBlock->pIndexData = NULL;
7420 break;
7422 default:
7423 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7424 break;
7428 /* Remove the resource from the resourceStore */
7429 device_resource_remove(This, resource);
7431 TRACE("Resource released\n");
7435 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7437 IWineD3DResourceImpl *resource, *cursor;
7438 HRESULT ret;
7439 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7441 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7442 TRACE("enumerating resource %p\n", resource);
7443 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7444 ret = pCallback((IWineD3DResource *) resource, pData);
7445 if(ret == S_FALSE) {
7446 TRACE("Canceling enumeration\n");
7447 break;
7450 return WINED3D_OK;
7453 /**********************************************************
7454 * IWineD3DDevice VTbl follows
7455 **********************************************************/
7457 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7459 /*** IUnknown methods ***/
7460 IWineD3DDeviceImpl_QueryInterface,
7461 IWineD3DDeviceImpl_AddRef,
7462 IWineD3DDeviceImpl_Release,
7463 /*** IWineD3DDevice methods ***/
7464 IWineD3DDeviceImpl_GetParent,
7465 /*** Creation methods**/
7466 IWineD3DDeviceImpl_CreateBuffer,
7467 IWineD3DDeviceImpl_CreateVertexBuffer,
7468 IWineD3DDeviceImpl_CreateIndexBuffer,
7469 IWineD3DDeviceImpl_CreateStateBlock,
7470 IWineD3DDeviceImpl_CreateSurface,
7471 IWineD3DDeviceImpl_CreateRendertargetView,
7472 IWineD3DDeviceImpl_CreateTexture,
7473 IWineD3DDeviceImpl_CreateVolumeTexture,
7474 IWineD3DDeviceImpl_CreateVolume,
7475 IWineD3DDeviceImpl_CreateCubeTexture,
7476 IWineD3DDeviceImpl_CreateQuery,
7477 IWineD3DDeviceImpl_CreateSwapChain,
7478 IWineD3DDeviceImpl_CreateVertexDeclaration,
7479 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7480 IWineD3DDeviceImpl_CreateVertexShader,
7481 IWineD3DDeviceImpl_CreatePixelShader,
7482 IWineD3DDeviceImpl_CreatePalette,
7483 /*** Odd functions **/
7484 IWineD3DDeviceImpl_Init3D,
7485 IWineD3DDeviceImpl_InitGDI,
7486 IWineD3DDeviceImpl_Uninit3D,
7487 IWineD3DDeviceImpl_UninitGDI,
7488 IWineD3DDeviceImpl_SetMultithreaded,
7489 IWineD3DDeviceImpl_EvictManagedResources,
7490 IWineD3DDeviceImpl_GetAvailableTextureMem,
7491 IWineD3DDeviceImpl_GetBackBuffer,
7492 IWineD3DDeviceImpl_GetCreationParameters,
7493 IWineD3DDeviceImpl_GetDeviceCaps,
7494 IWineD3DDeviceImpl_GetDirect3D,
7495 IWineD3DDeviceImpl_GetDisplayMode,
7496 IWineD3DDeviceImpl_SetDisplayMode,
7497 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7498 IWineD3DDeviceImpl_GetRasterStatus,
7499 IWineD3DDeviceImpl_GetSwapChain,
7500 IWineD3DDeviceImpl_Reset,
7501 IWineD3DDeviceImpl_SetDialogBoxMode,
7502 IWineD3DDeviceImpl_SetCursorProperties,
7503 IWineD3DDeviceImpl_SetCursorPosition,
7504 IWineD3DDeviceImpl_ShowCursor,
7505 IWineD3DDeviceImpl_TestCooperativeLevel,
7506 /*** Getters and setters **/
7507 IWineD3DDeviceImpl_SetClipPlane,
7508 IWineD3DDeviceImpl_GetClipPlane,
7509 IWineD3DDeviceImpl_SetClipStatus,
7510 IWineD3DDeviceImpl_GetClipStatus,
7511 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7512 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7513 IWineD3DDeviceImpl_SetDepthStencilSurface,
7514 IWineD3DDeviceImpl_GetDepthStencilSurface,
7515 IWineD3DDeviceImpl_SetGammaRamp,
7516 IWineD3DDeviceImpl_GetGammaRamp,
7517 IWineD3DDeviceImpl_SetIndices,
7518 IWineD3DDeviceImpl_GetIndices,
7519 IWineD3DDeviceImpl_SetBaseVertexIndex,
7520 IWineD3DDeviceImpl_GetBaseVertexIndex,
7521 IWineD3DDeviceImpl_SetLight,
7522 IWineD3DDeviceImpl_GetLight,
7523 IWineD3DDeviceImpl_SetLightEnable,
7524 IWineD3DDeviceImpl_GetLightEnable,
7525 IWineD3DDeviceImpl_SetMaterial,
7526 IWineD3DDeviceImpl_GetMaterial,
7527 IWineD3DDeviceImpl_SetNPatchMode,
7528 IWineD3DDeviceImpl_GetNPatchMode,
7529 IWineD3DDeviceImpl_SetPaletteEntries,
7530 IWineD3DDeviceImpl_GetPaletteEntries,
7531 IWineD3DDeviceImpl_SetPixelShader,
7532 IWineD3DDeviceImpl_GetPixelShader,
7533 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7534 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7535 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7536 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7537 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7538 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7539 IWineD3DDeviceImpl_SetRenderState,
7540 IWineD3DDeviceImpl_GetRenderState,
7541 IWineD3DDeviceImpl_SetRenderTarget,
7542 IWineD3DDeviceImpl_GetRenderTarget,
7543 IWineD3DDeviceImpl_SetFrontBackBuffers,
7544 IWineD3DDeviceImpl_SetSamplerState,
7545 IWineD3DDeviceImpl_GetSamplerState,
7546 IWineD3DDeviceImpl_SetScissorRect,
7547 IWineD3DDeviceImpl_GetScissorRect,
7548 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7549 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7550 IWineD3DDeviceImpl_SetStreamSource,
7551 IWineD3DDeviceImpl_GetStreamSource,
7552 IWineD3DDeviceImpl_SetStreamSourceFreq,
7553 IWineD3DDeviceImpl_GetStreamSourceFreq,
7554 IWineD3DDeviceImpl_SetTexture,
7555 IWineD3DDeviceImpl_GetTexture,
7556 IWineD3DDeviceImpl_SetTextureStageState,
7557 IWineD3DDeviceImpl_GetTextureStageState,
7558 IWineD3DDeviceImpl_SetTransform,
7559 IWineD3DDeviceImpl_GetTransform,
7560 IWineD3DDeviceImpl_SetVertexDeclaration,
7561 IWineD3DDeviceImpl_GetVertexDeclaration,
7562 IWineD3DDeviceImpl_SetVertexShader,
7563 IWineD3DDeviceImpl_GetVertexShader,
7564 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7565 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7566 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7567 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7568 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7569 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7570 IWineD3DDeviceImpl_SetViewport,
7571 IWineD3DDeviceImpl_GetViewport,
7572 IWineD3DDeviceImpl_MultiplyTransform,
7573 IWineD3DDeviceImpl_ValidateDevice,
7574 IWineD3DDeviceImpl_ProcessVertices,
7575 /*** State block ***/
7576 IWineD3DDeviceImpl_BeginStateBlock,
7577 IWineD3DDeviceImpl_EndStateBlock,
7578 /*** Scene management ***/
7579 IWineD3DDeviceImpl_BeginScene,
7580 IWineD3DDeviceImpl_EndScene,
7581 IWineD3DDeviceImpl_Present,
7582 IWineD3DDeviceImpl_Clear,
7583 IWineD3DDeviceImpl_ClearRendertargetView,
7584 /*** Drawing ***/
7585 IWineD3DDeviceImpl_SetPrimitiveType,
7586 IWineD3DDeviceImpl_GetPrimitiveType,
7587 IWineD3DDeviceImpl_DrawPrimitive,
7588 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7589 IWineD3DDeviceImpl_DrawPrimitiveUP,
7590 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7591 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7592 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7593 IWineD3DDeviceImpl_DrawRectPatch,
7594 IWineD3DDeviceImpl_DrawTriPatch,
7595 IWineD3DDeviceImpl_DeletePatch,
7596 IWineD3DDeviceImpl_ColorFill,
7597 IWineD3DDeviceImpl_UpdateTexture,
7598 IWineD3DDeviceImpl_UpdateSurface,
7599 IWineD3DDeviceImpl_GetFrontBufferData,
7600 /*** object tracking ***/
7601 IWineD3DDeviceImpl_EnumResources
7604 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7605 WINED3DRS_ALPHABLENDENABLE ,
7606 WINED3DRS_ALPHAFUNC ,
7607 WINED3DRS_ALPHAREF ,
7608 WINED3DRS_ALPHATESTENABLE ,
7609 WINED3DRS_BLENDOP ,
7610 WINED3DRS_COLORWRITEENABLE ,
7611 WINED3DRS_DESTBLEND ,
7612 WINED3DRS_DITHERENABLE ,
7613 WINED3DRS_FILLMODE ,
7614 WINED3DRS_FOGDENSITY ,
7615 WINED3DRS_FOGEND ,
7616 WINED3DRS_FOGSTART ,
7617 WINED3DRS_LASTPIXEL ,
7618 WINED3DRS_SHADEMODE ,
7619 WINED3DRS_SRCBLEND ,
7620 WINED3DRS_STENCILENABLE ,
7621 WINED3DRS_STENCILFAIL ,
7622 WINED3DRS_STENCILFUNC ,
7623 WINED3DRS_STENCILMASK ,
7624 WINED3DRS_STENCILPASS ,
7625 WINED3DRS_STENCILREF ,
7626 WINED3DRS_STENCILWRITEMASK ,
7627 WINED3DRS_STENCILZFAIL ,
7628 WINED3DRS_TEXTUREFACTOR ,
7629 WINED3DRS_WRAP0 ,
7630 WINED3DRS_WRAP1 ,
7631 WINED3DRS_WRAP2 ,
7632 WINED3DRS_WRAP3 ,
7633 WINED3DRS_WRAP4 ,
7634 WINED3DRS_WRAP5 ,
7635 WINED3DRS_WRAP6 ,
7636 WINED3DRS_WRAP7 ,
7637 WINED3DRS_ZENABLE ,
7638 WINED3DRS_ZFUNC ,
7639 WINED3DRS_ZWRITEENABLE
7642 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7643 WINED3DTSS_ALPHAARG0 ,
7644 WINED3DTSS_ALPHAARG1 ,
7645 WINED3DTSS_ALPHAARG2 ,
7646 WINED3DTSS_ALPHAOP ,
7647 WINED3DTSS_BUMPENVLOFFSET ,
7648 WINED3DTSS_BUMPENVLSCALE ,
7649 WINED3DTSS_BUMPENVMAT00 ,
7650 WINED3DTSS_BUMPENVMAT01 ,
7651 WINED3DTSS_BUMPENVMAT10 ,
7652 WINED3DTSS_BUMPENVMAT11 ,
7653 WINED3DTSS_COLORARG0 ,
7654 WINED3DTSS_COLORARG1 ,
7655 WINED3DTSS_COLORARG2 ,
7656 WINED3DTSS_COLOROP ,
7657 WINED3DTSS_RESULTARG ,
7658 WINED3DTSS_TEXCOORDINDEX ,
7659 WINED3DTSS_TEXTURETRANSFORMFLAGS
7662 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7663 WINED3DSAMP_ADDRESSU ,
7664 WINED3DSAMP_ADDRESSV ,
7665 WINED3DSAMP_ADDRESSW ,
7666 WINED3DSAMP_BORDERCOLOR ,
7667 WINED3DSAMP_MAGFILTER ,
7668 WINED3DSAMP_MINFILTER ,
7669 WINED3DSAMP_MIPFILTER ,
7670 WINED3DSAMP_MIPMAPLODBIAS ,
7671 WINED3DSAMP_MAXMIPLEVEL ,
7672 WINED3DSAMP_MAXANISOTROPY ,
7673 WINED3DSAMP_SRGBTEXTURE ,
7674 WINED3DSAMP_ELEMENTINDEX
7677 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7678 WINED3DRS_AMBIENT ,
7679 WINED3DRS_AMBIENTMATERIALSOURCE ,
7680 WINED3DRS_CLIPPING ,
7681 WINED3DRS_CLIPPLANEENABLE ,
7682 WINED3DRS_COLORVERTEX ,
7683 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7684 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7685 WINED3DRS_FOGDENSITY ,
7686 WINED3DRS_FOGEND ,
7687 WINED3DRS_FOGSTART ,
7688 WINED3DRS_FOGTABLEMODE ,
7689 WINED3DRS_FOGVERTEXMODE ,
7690 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7691 WINED3DRS_LIGHTING ,
7692 WINED3DRS_LOCALVIEWER ,
7693 WINED3DRS_MULTISAMPLEANTIALIAS ,
7694 WINED3DRS_MULTISAMPLEMASK ,
7695 WINED3DRS_NORMALIZENORMALS ,
7696 WINED3DRS_PATCHEDGESTYLE ,
7697 WINED3DRS_POINTSCALE_A ,
7698 WINED3DRS_POINTSCALE_B ,
7699 WINED3DRS_POINTSCALE_C ,
7700 WINED3DRS_POINTSCALEENABLE ,
7701 WINED3DRS_POINTSIZE ,
7702 WINED3DRS_POINTSIZE_MAX ,
7703 WINED3DRS_POINTSIZE_MIN ,
7704 WINED3DRS_POINTSPRITEENABLE ,
7705 WINED3DRS_RANGEFOGENABLE ,
7706 WINED3DRS_SPECULARMATERIALSOURCE ,
7707 WINED3DRS_TWEENFACTOR ,
7708 WINED3DRS_VERTEXBLEND ,
7709 WINED3DRS_CULLMODE ,
7710 WINED3DRS_FOGCOLOR
7713 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7714 WINED3DTSS_TEXCOORDINDEX ,
7715 WINED3DTSS_TEXTURETRANSFORMFLAGS
7718 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7719 WINED3DSAMP_DMAPOFFSET
7722 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7723 DWORD rep = This->StateTable[state].representative;
7724 DWORD idx;
7725 BYTE shift;
7726 UINT i;
7727 WineD3DContext *context;
7729 if(!rep) return;
7730 for(i = 0; i < This->numContexts; i++) {
7731 context = This->contexts[i];
7732 if(isStateDirty(context, rep)) continue;
7734 context->dirtyArray[context->numDirtyEntries++] = rep;
7735 idx = rep >> 5;
7736 shift = rep & 0x1f;
7737 context->isStateDirty[idx] |= (1 << shift);
7741 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7742 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7743 /* The drawable size of a pbuffer render target is the current pbuffer size
7745 *width = dev->pbufferWidth;
7746 *height = dev->pbufferHeight;
7749 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7750 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7752 *width = This->pow2Width;
7753 *height = This->pow2Height;
7756 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7757 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7758 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7759 * current context's drawable, which is the size of the back buffer of the swapchain
7760 * the active context belongs to. The back buffer of the swapchain is stored as the
7761 * surface the context belongs to.
7763 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7764 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;