dpwsockx: Implementation of SPInit
[wine/gsoc_dplay.git] / dlls / wined3d / device.c
blob58e3b699d95ec7bdedcf3cb728c7fb6860506e3c
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.0f, 1.0f, 1.0f, 0.0f }, /* Diffuse r,g,b,a */
43 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Specular r,g,b,a */
44 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Ambient r,g,b,a, */
45 { 0.0f, 0.0f, 0.0f }, /* Position x,y,z */
46 { 0.0f, 0.0f, 1.0f }, /* Direction x,y,z */
47 0.0f, /* Range */
48 0.0f, /* Falloff */
49 0.0f, 0.0f, 0.0f, /* Attenuation 0,1,2 */
50 0.0f, /* Theta */
51 0.0f /* Phi */
54 /**********************************************************
55 * Global variable / Constants follow
56 **********************************************************/
57 const float identity[] =
59 1.0f, 0.0f, 0.0f, 0.0f,
60 0.0f, 1.0f, 0.0f, 0.0f,
61 0.0f, 0.0f, 1.0f, 0.0f,
62 0.0f, 0.0f, 0.0f, 1.0f,
63 }; /* When needed for comparisons */
65 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
66 * actually have the same values in GL and D3D. */
67 static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
69 switch(primitive_type)
71 case WINED3DPT_POINTLIST:
72 return GL_POINTS;
74 case WINED3DPT_LINELIST:
75 return GL_LINES;
77 case WINED3DPT_LINESTRIP:
78 return GL_LINE_STRIP;
80 case WINED3DPT_TRIANGLELIST:
81 return GL_TRIANGLES;
83 case WINED3DPT_TRIANGLESTRIP:
84 return GL_TRIANGLE_STRIP;
86 case WINED3DPT_TRIANGLEFAN:
87 return GL_TRIANGLE_FAN;
89 case WINED3DPT_LINELIST_ADJ:
90 return GL_LINES_ADJACENCY_ARB;
92 case WINED3DPT_LINESTRIP_ADJ:
93 return GL_LINE_STRIP_ADJACENCY_ARB;
95 case WINED3DPT_TRIANGLELIST_ADJ:
96 return GL_TRIANGLES_ADJACENCY_ARB;
98 case WINED3DPT_TRIANGLESTRIP_ADJ:
99 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
101 default:
102 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
103 return GL_NONE;
107 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
109 switch(primitive_type)
111 case GL_POINTS:
112 return WINED3DPT_POINTLIST;
114 case GL_LINES:
115 return WINED3DPT_LINELIST;
117 case GL_LINE_STRIP:
118 return WINED3DPT_LINESTRIP;
120 case GL_TRIANGLES:
121 return WINED3DPT_TRIANGLELIST;
123 case GL_TRIANGLE_STRIP:
124 return WINED3DPT_TRIANGLESTRIP;
126 case GL_TRIANGLE_FAN:
127 return WINED3DPT_TRIANGLEFAN;
129 case GL_LINES_ADJACENCY_ARB:
130 return WINED3DPT_LINELIST_ADJ;
132 case GL_LINE_STRIP_ADJACENCY_ARB:
133 return WINED3DPT_LINESTRIP_ADJ;
135 case GL_TRIANGLES_ADJACENCY_ARB:
136 return WINED3DPT_TRIANGLELIST_ADJ;
138 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
139 return WINED3DPT_TRIANGLESTRIP_ADJ;
141 default:
142 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
143 return WINED3DPT_UNDEFINED;
147 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
149 if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && usage_idx == 0)
150 *regnum = WINED3D_FFP_POSITION;
151 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
152 *regnum = WINED3D_FFP_BLENDWEIGHT;
153 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
154 *regnum = WINED3D_FFP_BLENDINDICES;
155 else if (usage == WINED3DDECLUSAGE_NORMAL && usage_idx == 0)
156 *regnum = WINED3D_FFP_NORMAL;
157 else if (usage == WINED3DDECLUSAGE_PSIZE && usage_idx == 0)
158 *regnum = WINED3D_FFP_PSIZE;
159 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 0)
160 *regnum = WINED3D_FFP_DIFFUSE;
161 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1)
162 *regnum = WINED3D_FFP_SPECULAR;
163 else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
164 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
165 else
167 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
168 *regnum = ~0U;
169 return FALSE;
172 return TRUE;
175 /* Context activation is done by the caller. */
176 void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
177 BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
179 /* We need to deal with frequency data! */
180 IWineD3DVertexDeclarationImpl *declaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
181 UINT stream_count = This->stateBlock->streamIsUP ? 0 : declaration->num_streams;
182 const DWORD *streams = declaration->streams;
183 unsigned int i;
185 stream_info->use_map = 0;
186 stream_info->swizzle_map = 0;
188 /* Check for transformed vertices, disable vertex shader if present. */
189 stream_info->position_transformed = declaration->position_transformed;
190 if (declaration->position_transformed) use_vshader = FALSE;
192 /* Translate the declaration into strided data. */
193 for (i = 0; i < declaration->element_count; ++i)
195 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
196 GLuint buffer_object = 0;
197 const BYTE *data = NULL;
198 BOOL stride_used;
199 unsigned int idx;
200 DWORD stride;
202 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
203 element, i + 1, declaration->element_count);
205 if (!This->stateBlock->streamSource[element->input_slot]) continue;
207 stride = This->stateBlock->streamStride[element->input_slot];
208 if (This->stateBlock->streamIsUP)
210 TRACE("Stream %u is UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
211 buffer_object = 0;
212 data = (BYTE *)This->stateBlock->streamSource[element->input_slot];
214 else
216 TRACE("Stream %u isn't UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
217 data = buffer_get_memory(This->stateBlock->streamSource[element->input_slot], 0, &buffer_object);
219 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
220 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
221 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
222 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
223 * not, drawStridedSlow is needed, including a vertex buffer path. */
224 if (This->stateBlock->loadBaseVertexIndex < 0)
226 WARN("loadBaseVertexIndex is < 0 (%d), not using vbos\n", This->stateBlock->loadBaseVertexIndex);
227 buffer_object = 0;
228 data = buffer_get_sysmem((struct wined3d_buffer *)This->stateBlock->streamSource[element->input_slot]);
229 if ((UINT_PTR)data < -This->stateBlock->loadBaseVertexIndex * stride)
231 FIXME("System memory vertex data load offset is negative!\n");
235 if (fixup)
237 if (buffer_object) *fixup = TRUE;
238 else if (*fixup && !use_vshader
239 && (element->usage == WINED3DDECLUSAGE_COLOR
240 || element->usage == WINED3DDECLUSAGE_POSITIONT))
242 static BOOL warned = FALSE;
243 if (!warned)
245 /* This may be bad with the fixed function pipeline. */
246 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
247 warned = TRUE;
252 data += element->offset;
254 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
256 if (use_vshader)
258 if (element->output_slot == ~0U)
260 /* TODO: Assuming vertexdeclarations are usually used with the
261 * same or a similar shader, it might be worth it to store the
262 * last used output slot and try that one first. */
263 stride_used = vshader_get_input(This->stateBlock->vertexShader,
264 element->usage, element->usage_idx, &idx);
266 else
268 idx = element->output_slot;
269 stride_used = TRUE;
272 else
274 if (!element->ffp_valid)
276 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
277 debug_d3dformat(element->format_desc->format), debug_d3ddeclusage(element->usage));
278 stride_used = FALSE;
280 else
282 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
286 if (stride_used)
288 TRACE("Load %s array %u [usage %s, usage_idx %u, "
289 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
290 use_vshader ? "shader": "fixed function", idx,
291 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
292 element->offset, stride, debug_d3dformat(element->format_desc->format), buffer_object);
294 stream_info->elements[idx].format_desc = element->format_desc;
295 stream_info->elements[idx].stride = stride;
296 stream_info->elements[idx].data = data;
297 stream_info->elements[idx].stream_idx = element->input_slot;
298 stream_info->elements[idx].buffer_object = buffer_object;
300 if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA) && element->format_desc->format == WINED3DFMT_A8R8G8B8)
302 stream_info->swizzle_map |= 1 << idx;
304 stream_info->use_map |= 1 << idx;
308 /* Now call PreLoad on all the vertex buffers. In the very rare case
309 * that the buffers stopps converting PreLoad will dirtify the VDECL again.
310 * The vertex buffer can now use the strided structure in the device instead of finding its
311 * own again.
313 * NULL streams won't be recorded in the array, UP streams won't be either. A stream is only
314 * once in there. */
315 for (i = 0; i < stream_count; ++i)
317 IWineD3DBuffer *vb = This->stateBlock->streamSource[streams[i]];
318 if (vb) IWineD3DBuffer_PreLoad(vb);
322 static void stream_info_element_from_strided(IWineD3DDeviceImpl *This,
323 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
325 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(strided->format, &This->adapter->gl_info);
326 e->format_desc = format_desc;
327 e->stride = strided->dwStride;
328 e->data = strided->lpData;
329 e->stream_idx = 0;
330 e->buffer_object = 0;
333 void device_stream_info_from_strided(IWineD3DDeviceImpl *This,
334 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
336 unsigned int i;
338 memset(stream_info, 0, sizeof(*stream_info));
340 if (strided->position.lpData)
341 stream_info_element_from_strided(This, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
342 if (strided->normal.lpData)
343 stream_info_element_from_strided(This, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
344 if (strided->diffuse.lpData)
345 stream_info_element_from_strided(This, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
346 if (strided->specular.lpData)
347 stream_info_element_from_strided(This, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
349 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
351 if (strided->texCoords[i].lpData)
352 stream_info_element_from_strided(This, &strided->texCoords[i],
353 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
356 stream_info->position_transformed = strided->position_transformed;
358 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
360 if (!stream_info->elements[i].format_desc) continue;
362 if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA) && stream_info->elements[i].format_desc->format == WINED3DFMT_A8R8G8B8)
364 stream_info->swizzle_map |= 1 << i;
366 stream_info->use_map |= 1 << i;
370 /**********************************************************
371 * IUnknown parts follows
372 **********************************************************/
374 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
376 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
378 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
379 if (IsEqualGUID(riid, &IID_IUnknown)
380 || IsEqualGUID(riid, &IID_IWineD3DBase)
381 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
382 IUnknown_AddRef(iface);
383 *ppobj = This;
384 return S_OK;
386 *ppobj = NULL;
387 return E_NOINTERFACE;
390 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
391 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
392 ULONG refCount = InterlockedIncrement(&This->ref);
394 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
395 return refCount;
398 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
400 ULONG refCount = InterlockedDecrement(&This->ref);
402 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
404 if (!refCount) {
405 UINT i;
407 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
408 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
409 This->multistate_funcs[i] = NULL;
412 /* TODO: Clean up all the surfaces and textures! */
413 /* NOTE: You must release the parent if the object was created via a callback
414 ** ***************************/
416 if (!list_empty(&This->resources)) {
417 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
418 dumpResources(&This->resources);
421 if(This->contexts) ERR("Context array not freed!\n");
422 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
423 This->haveHardwareCursor = FALSE;
425 IWineD3D_Release(This->wineD3D);
426 This->wineD3D = NULL;
427 HeapFree(GetProcessHeap(), 0, This);
428 TRACE("Freed device %p\n", This);
429 This = NULL;
431 return refCount;
434 /**********************************************************
435 * IWineD3DDevice implementation follows
436 **********************************************************/
437 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
439 *pParent = This->parent;
440 IUnknown_AddRef(This->parent);
441 return WINED3D_OK;
444 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface,
445 struct wined3d_buffer_desc *desc, const void *data, IUnknown *parent, IWineD3DBuffer **buffer)
447 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
448 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(WINED3DFMT_UNKNOWN, &This->adapter->gl_info);
449 struct wined3d_buffer *object;
450 HRESULT hr;
452 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
454 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
455 if (!object)
457 ERR("Failed to allocate memory\n");
458 return E_OUTOFMEMORY;
461 object->vtbl = &wined3d_buffer_vtbl;
462 object->desc = *desc;
464 FIXME("Ignoring access flags (pool)\n");
466 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_BUFFER, This, desc->byte_width,
467 desc->usage, format_desc, WINED3DPOOL_MANAGED, parent);
468 if (FAILED(hr))
470 WARN("Failed to initialize resource, returning %#x\n", hr);
471 HeapFree(GetProcessHeap(), 0, object);
472 return hr;
474 object->buffer_type_hint = GL_ARRAY_BUFFER_ARB;
476 TRACE("Created resource %p\n", object);
478 TRACE("size %#x, usage=%#x, format %s, memory @ %p, iface @ %p\n", object->resource.size, object->resource.usage,
479 debug_d3dformat(object->resource.format_desc->format), object->resource.allocatedMemory, object);
481 if (data)
483 BYTE *ptr;
485 hr = IWineD3DBuffer_Map((IWineD3DBuffer *)object, 0, desc->byte_width, &ptr, 0);
486 if (FAILED(hr))
488 ERR("Failed to map buffer, hr %#x\n", hr);
489 IWineD3DBuffer_Release((IWineD3DBuffer *)object);
490 return hr;
493 memcpy(ptr, data, desc->byte_width);
495 hr = IWineD3DBuffer_Unmap((IWineD3DBuffer *)object);
496 if (FAILED(hr))
498 ERR("Failed to unmap buffer, hr %#x\n", hr);
499 IWineD3DBuffer_Release((IWineD3DBuffer *)object);
500 return hr;
504 *buffer = (IWineD3DBuffer *)object;
506 return WINED3D_OK;
509 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
510 DWORD FVF, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer, IUnknown *parent)
512 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
513 /* Dummy format for now */
514 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(WINED3DFMT_VERTEXDATA, &This->adapter->gl_info);
515 struct wined3d_buffer *object;
516 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
517 HRESULT hr;
518 BOOL conv;
520 if(Size == 0) {
521 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
522 *ppVertexBuffer = NULL;
523 return WINED3DERR_INVALIDCALL;
524 } else if(Pool == WINED3DPOOL_SCRATCH) {
525 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
526 * anyway, SCRATCH vertex buffers aren't usable anywhere
528 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
529 *ppVertexBuffer = NULL;
530 return WINED3DERR_INVALIDCALL;
533 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
534 if (!object)
536 ERR("Out of memory\n");
537 *ppVertexBuffer = NULL;
538 return WINED3DERR_OUTOFVIDEOMEMORY;
541 object->vtbl = &wined3d_buffer_vtbl;
542 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_BUFFER, This, Size, Usage, format_desc, Pool, parent);
543 if (FAILED(hr))
545 WARN("Failed to initialize resource, returning %#x\n", hr);
546 HeapFree(GetProcessHeap(), 0, object);
547 *ppVertexBuffer = NULL;
548 return hr;
550 object->buffer_type_hint = GL_ARRAY_BUFFER_ARB;
552 TRACE("(%p) : Created resource %p\n", This, object);
554 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);
555 *ppVertexBuffer = (IWineD3DBuffer *)object;
557 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
558 * drawStridedFast (half-life 2).
560 * Basically converting the vertices in the buffer is quite expensive, and observations
561 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
562 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
564 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
565 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
566 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
567 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
568 * dx7 apps.
569 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
570 * more. In this call we can convert dx7 buffers too.
572 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
573 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
574 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
575 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
576 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
577 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
578 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
579 } else if(dxVersion <= 7 && conv) {
580 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
581 } else {
582 object->flags |= WINED3D_BUFFER_CREATEBO;
584 return WINED3D_OK;
587 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
588 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer, IUnknown *parent)
590 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
591 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(WINED3DFMT_UNKNOWN, &This->adapter->gl_info);
592 struct wined3d_buffer *object;
593 HRESULT hr;
595 TRACE("(%p) Creating index buffer\n", This);
597 /* Allocate the storage for the device */
598 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
599 if (!object)
601 ERR("Out of memory\n");
602 *ppIndexBuffer = NULL;
603 return WINED3DERR_OUTOFVIDEOMEMORY;
606 object->vtbl = &wined3d_buffer_vtbl;
607 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_BUFFER, This, Length, Usage, format_desc, Pool, parent);
608 if (FAILED(hr))
610 WARN("Failed to initialize resource, returning %#x\n", hr);
611 HeapFree(GetProcessHeap(), 0, object);
612 *ppIndexBuffer = NULL;
613 return hr;
615 object->buffer_type_hint = GL_ELEMENT_ARRAY_BUFFER_ARB;
617 TRACE("(%p) : Created resource %p\n", This, object);
619 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
620 object->flags |= WINED3D_BUFFER_CREATEBO;
623 TRACE("(%p) : Len=%d, Use=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage,
624 Pool, object, object->resource.allocatedMemory);
625 *ppIndexBuffer = (IWineD3DBuffer *) object;
627 return WINED3D_OK;
630 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
632 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
633 IWineD3DStateBlockImpl *object;
634 unsigned int i, j;
635 HRESULT temp_result;
637 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
638 if(!object)
640 ERR("Out of memory\n");
641 *ppStateBlock = NULL;
642 return WINED3DERR_OUTOFVIDEOMEMORY;
645 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
646 object->wineD3DDevice = This;
647 object->parent = parent;
648 object->ref = 1;
649 object->blockType = Type;
651 *ppStateBlock = (IWineD3DStateBlock *)object;
653 for(i = 0; i < LIGHTMAP_SIZE; i++) {
654 list_init(&object->lightMap[i]);
657 temp_result = allocate_shader_constants(object);
658 if (FAILED(temp_result))
660 HeapFree(GetProcessHeap(), 0, object);
661 return temp_result;
664 /* Special case - Used during initialization to produce a placeholder stateblock
665 so other functions called can update a state block */
666 if (Type == WINED3DSBT_INIT || Type == WINED3DSBT_RECORDED)
668 /* Don't bother increasing the reference count otherwise a device will never
669 be freed due to circular dependencies */
670 return WINED3D_OK;
673 /* Otherwise, might as well set the whole state block to the appropriate values */
674 if (This->stateBlock != NULL)
675 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
676 else
677 memset(object->streamFreq, 1, sizeof(object->streamFreq));
679 /* Reset the ref and type after kludging it */
680 object->wineD3DDevice = This;
681 object->ref = 1;
682 object->blockType = Type;
684 TRACE("Updating changed flags appropriate for type %d\n", Type);
686 if (Type == WINED3DSBT_ALL) {
688 TRACE("ALL => Pretend everything has changed\n");
689 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
691 /* Lights are not part of the changed / set structure */
692 for(j = 0; j < LIGHTMAP_SIZE; j++) {
693 struct list *e;
694 LIST_FOR_EACH(e, &object->lightMap[j]) {
695 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
696 light->changed = TRUE;
697 light->enabledChanged = TRUE;
700 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
701 object->contained_render_states[j - 1] = j;
703 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
704 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
705 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
706 object->contained_transform_states[j - 1] = j;
708 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
709 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
710 object->contained_vs_consts_f[j] = j;
712 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
713 for(j = 0; j < MAX_CONST_I; j++) {
714 object->contained_vs_consts_i[j] = j;
716 object->num_contained_vs_consts_i = MAX_CONST_I;
717 for(j = 0; j < MAX_CONST_B; j++) {
718 object->contained_vs_consts_b[j] = j;
720 object->num_contained_vs_consts_b = MAX_CONST_B;
721 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
722 object->contained_ps_consts_f[j] = j;
724 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
725 for(j = 0; j < MAX_CONST_I; j++) {
726 object->contained_ps_consts_i[j] = j;
728 object->num_contained_ps_consts_i = MAX_CONST_I;
729 for(j = 0; j < MAX_CONST_B; j++) {
730 object->contained_ps_consts_b[j] = j;
732 object->num_contained_ps_consts_b = MAX_CONST_B;
733 for(i = 0; i < MAX_TEXTURES; i++) {
734 for (j = 0; j <= WINED3D_HIGHEST_TEXTURE_STATE; ++j)
736 object->contained_tss_states[object->num_contained_tss_states].stage = i;
737 object->contained_tss_states[object->num_contained_tss_states].state = j;
738 object->num_contained_tss_states++;
741 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
742 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
743 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
744 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
745 object->num_contained_sampler_states++;
749 for(i = 0; i < MAX_STREAMS; i++) {
750 if(object->streamSource[i]) {
751 IWineD3DBuffer_AddRef(object->streamSource[i]);
754 if(object->pIndexData) {
755 IWineD3DBuffer_AddRef(object->pIndexData);
757 if(object->vertexShader) {
758 IWineD3DVertexShader_AddRef(object->vertexShader);
760 if(object->pixelShader) {
761 IWineD3DPixelShader_AddRef(object->pixelShader);
764 } else if (Type == WINED3DSBT_PIXELSTATE) {
766 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
767 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
769 object->changed.pixelShader = TRUE;
771 /* Pixel Shader Constants */
772 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
773 object->contained_ps_consts_f[i] = i;
774 object->changed.pixelShaderConstantsF[i] = TRUE;
776 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
777 for (i = 0; i < MAX_CONST_B; ++i) {
778 object->contained_ps_consts_b[i] = i;
779 object->changed.pixelShaderConstantsB |= (1 << i);
781 object->num_contained_ps_consts_b = MAX_CONST_B;
782 for (i = 0; i < MAX_CONST_I; ++i) {
783 object->contained_ps_consts_i[i] = i;
784 object->changed.pixelShaderConstantsI |= (1 << i);
786 object->num_contained_ps_consts_i = MAX_CONST_I;
788 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
789 DWORD rs = SavedPixelStates_R[i];
790 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
791 object->contained_render_states[i] = rs;
793 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
794 for (j = 0; j < MAX_TEXTURES; j++) {
795 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
796 DWORD state = SavedPixelStates_T[i];
797 object->changed.textureState[j] |= 1 << state;
798 object->contained_tss_states[object->num_contained_tss_states].stage = j;
799 object->contained_tss_states[object->num_contained_tss_states].state = state;
800 object->num_contained_tss_states++;
803 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
804 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
805 DWORD state = SavedPixelStates_S[i];
806 object->changed.samplerState[j] |= 1 << state;
807 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
808 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
809 object->num_contained_sampler_states++;
812 if(object->pixelShader) {
813 IWineD3DPixelShader_AddRef(object->pixelShader);
816 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
817 * on them. This makes releasing the buffer easier
819 for(i = 0; i < MAX_STREAMS; i++) {
820 object->streamSource[i] = NULL;
822 object->pIndexData = NULL;
823 object->vertexShader = NULL;
825 } else if (Type == WINED3DSBT_VERTEXSTATE) {
827 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
828 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
830 object->changed.vertexShader = TRUE;
832 /* Vertex Shader Constants */
833 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
834 object->changed.vertexShaderConstantsF[i] = TRUE;
835 object->contained_vs_consts_f[i] = i;
837 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
838 for (i = 0; i < MAX_CONST_B; ++i) {
839 object->contained_vs_consts_b[i] = i;
840 object->changed.vertexShaderConstantsB |= (1 << i);
842 object->num_contained_vs_consts_b = MAX_CONST_B;
843 for (i = 0; i < MAX_CONST_I; ++i) {
844 object->contained_vs_consts_i[i] = i;
845 object->changed.vertexShaderConstantsI |= (1 << i);
847 object->num_contained_vs_consts_i = MAX_CONST_I;
848 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
849 DWORD rs = SavedVertexStates_R[i];
850 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
851 object->contained_render_states[i] = rs;
853 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
854 for (j = 0; j < MAX_TEXTURES; j++) {
855 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
856 DWORD state = SavedVertexStates_T[i];
857 object->changed.textureState[j] |= 1 << state;
858 object->contained_tss_states[object->num_contained_tss_states].stage = j;
859 object->contained_tss_states[object->num_contained_tss_states].state = state;
860 object->num_contained_tss_states++;
863 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
864 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
865 DWORD state = SavedVertexStates_S[i];
866 object->changed.samplerState[j] |= 1 << state;
867 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
868 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
869 object->num_contained_sampler_states++;
873 for(j = 0; j < LIGHTMAP_SIZE; j++) {
874 struct list *e;
875 LIST_FOR_EACH(e, &object->lightMap[j]) {
876 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
877 light->changed = TRUE;
878 light->enabledChanged = TRUE;
882 for(i = 0; i < MAX_STREAMS; i++) {
883 if(object->streamSource[i]) {
884 IWineD3DBuffer_AddRef(object->streamSource[i]);
887 if(object->vertexShader) {
888 IWineD3DVertexShader_AddRef(object->vertexShader);
890 object->pIndexData = NULL;
891 object->pixelShader = NULL;
892 } else {
893 FIXME("Unrecognized state block type %d\n", Type);
896 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
897 return WINED3D_OK;
900 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
901 WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,
902 DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
903 WINED3DSURFTYPE Impl, IUnknown *parent)
905 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
906 IWineD3DSurfaceImpl *object;
907 HRESULT hr;
909 TRACE("(%p) Create surface\n",This);
911 if (Impl == SURFACE_OPENGL && !This->adapter)
913 ERR("OpenGL surfaces are not available without OpenGL.\n");
914 return WINED3DERR_NOTAVAILABLE;
917 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
918 if (!object)
920 ERR("Failed to allocate surface memory.\n");
921 *ppSurface = NULL;
922 return WINED3DERR_OUTOFVIDEOMEMORY;
925 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
926 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent);
927 if (FAILED(hr))
929 WARN("Failed to initialize surface, returning %#x.\n", hr);
930 HeapFree(GetProcessHeap(), 0, object);
931 *ppSurface = NULL;
932 return hr;
935 TRACE("(%p) : Created surface %p\n", This, object);
937 *ppSurface = (IWineD3DSurface *)object;
939 return hr;
942 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
943 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
945 struct wined3d_rendertarget_view *object;
947 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
948 if (!object)
950 ERR("Failed to allocate memory\n");
951 return E_OUTOFMEMORY;
954 object->vtbl = &wined3d_rendertarget_view_vtbl;
955 object->refcount = 1;
956 IWineD3DResource_AddRef(resource);
957 object->resource = resource;
958 object->parent = parent;
960 *rendertarget_view = (IWineD3DRendertargetView *)object;
962 return WINED3D_OK;
965 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
966 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
967 WINED3DPOOL Pool, IWineD3DTexture **ppTexture, IUnknown *parent)
969 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
970 IWineD3DTextureImpl *object;
971 HRESULT hr;
973 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
974 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
975 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
977 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
978 if (!object)
980 ERR("Out of memory\n");
981 *ppTexture = NULL;
982 return WINED3DERR_OUTOFVIDEOMEMORY;
985 object->lpVtbl = &IWineD3DTexture_Vtbl;
987 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent);
988 if (FAILED(hr))
990 WARN("Failed to initialize texture, returning %#x\n", hr);
991 HeapFree(GetProcessHeap(), 0, object);
992 *ppTexture = NULL;
993 return hr;
996 *ppTexture = (IWineD3DTexture *)object;
998 TRACE("(%p) : Created texture %p\n", This, object);
1000 return WINED3D_OK;
1003 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1004 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
1005 WINED3DPOOL Pool, IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent)
1007 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1008 IWineD3DVolumeTextureImpl *object;
1009 HRESULT hr;
1011 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1012 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1014 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1015 if (!object)
1017 ERR("Out of memory\n");
1018 *ppVolumeTexture = NULL;
1019 return WINED3DERR_OUTOFVIDEOMEMORY;
1022 object->lpVtbl = &IWineD3DVolumeTexture_Vtbl;
1023 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent);
1024 if (FAILED(hr))
1026 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
1027 HeapFree(GetProcessHeap(), 0, object);
1028 *ppVolumeTexture = NULL;
1029 return hr;
1032 TRACE("(%p) : Created volume texture %p.\n", This, object);
1033 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
1035 return WINED3D_OK;
1038 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1039 UINT Width, UINT Height, UINT Depth, DWORD Usage, WINED3DFORMAT Format,
1040 WINED3DPOOL Pool, IWineD3DVolume **ppVolume, IUnknown *parent)
1042 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1043 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1044 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &GLINFO_LOCATION);
1045 HRESULT hr;
1047 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1048 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1049 return WINED3DERR_INVALIDCALL;
1052 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1053 if (!object)
1055 ERR("Out of memory\n");
1056 *ppVolume = NULL;
1057 return WINED3DERR_OUTOFVIDEOMEMORY;
1060 object->lpVtbl = &IWineD3DVolume_Vtbl;
1061 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_VOLUME, This,
1062 Width * Height * Depth * format_desc->byte_count, Usage, format_desc, Pool, parent);
1063 if (FAILED(hr))
1065 WARN("Failed to initialize resource, returning %#x\n", hr);
1066 HeapFree(GetProcessHeap(), 0, object);
1067 *ppVolume = NULL;
1068 return hr;
1071 TRACE("(%p) : Created resource %p\n", This, object);
1073 *ppVolume = (IWineD3DVolume *)object;
1075 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1076 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1078 object->currentDesc.Width = Width;
1079 object->currentDesc.Height = Height;
1080 object->currentDesc.Depth = Depth;
1082 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1083 object->lockable = TRUE;
1084 object->locked = FALSE;
1085 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1086 object->dirty = TRUE;
1088 volume_add_dirty_box((IWineD3DVolume *)object, NULL);
1090 return WINED3D_OK;
1093 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface,
1094 UINT EdgeLength, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
1095 WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture, IUnknown *parent)
1097 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1098 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1099 HRESULT hr;
1101 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1102 if (!object)
1104 ERR("Out of memory\n");
1105 *ppCubeTexture = NULL;
1106 return WINED3DERR_OUTOFVIDEOMEMORY;
1109 object->lpVtbl = &IWineD3DCubeTexture_Vtbl;
1110 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent);
1111 if (FAILED(hr))
1113 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1114 HeapFree(GetProcessHeap(), 0, object);
1115 *ppCubeTexture = NULL;
1116 return hr;
1119 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1120 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1122 return WINED3D_OK;
1125 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1126 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1127 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1128 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1129 const IWineD3DQueryVtbl *vtable;
1131 /* Just a check to see if we support this type of query */
1132 switch(Type) {
1133 case WINED3DQUERYTYPE_OCCLUSION:
1134 TRACE("(%p) occlusion query\n", This);
1135 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1136 hr = WINED3D_OK;
1137 else
1138 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1140 vtable = &IWineD3DOcclusionQuery_Vtbl;
1141 break;
1143 case WINED3DQUERYTYPE_EVENT:
1144 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1145 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1146 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1148 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1150 vtable = &IWineD3DEventQuery_Vtbl;
1151 hr = WINED3D_OK;
1152 break;
1154 case WINED3DQUERYTYPE_VCACHE:
1155 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1156 case WINED3DQUERYTYPE_VERTEXSTATS:
1157 case WINED3DQUERYTYPE_TIMESTAMP:
1158 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1159 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1160 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1161 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1162 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1163 case WINED3DQUERYTYPE_PIXELTIMINGS:
1164 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1165 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1166 default:
1167 /* Use the base Query vtable until we have a special one for each query */
1168 vtable = &IWineD3DQuery_Vtbl;
1169 FIXME("(%p) Unhandled query type %d\n", This, Type);
1171 if(NULL == ppQuery || hr != WINED3D_OK) {
1172 return hr;
1175 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1176 if(!object)
1178 ERR("Out of memory\n");
1179 *ppQuery = NULL;
1180 return WINED3DERR_OUTOFVIDEOMEMORY;
1183 object->lpVtbl = vtable;
1184 object->type = Type;
1185 object->state = QUERY_CREATED;
1186 object->wineD3DDevice = This;
1187 object->parent = parent;
1188 object->ref = 1;
1190 *ppQuery = (IWineD3DQuery *)object;
1192 /* allocated the 'extended' data based on the type of query requested */
1193 switch(Type){
1194 case WINED3DQUERYTYPE_OCCLUSION:
1195 object->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_occlusion_query));
1196 ((struct wined3d_occlusion_query *)object->extendedData)->context = NULL;
1197 break;
1199 case WINED3DQUERYTYPE_EVENT:
1200 object->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_event_query));
1201 ((struct wined3d_event_query *)object->extendedData)->context = NULL;
1202 break;
1204 case WINED3DQUERYTYPE_VCACHE:
1205 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1206 case WINED3DQUERYTYPE_VERTEXSTATS:
1207 case WINED3DQUERYTYPE_TIMESTAMP:
1208 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1209 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1210 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1211 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1212 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1213 case WINED3DQUERYTYPE_PIXELTIMINGS:
1214 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1215 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1216 default:
1217 object->extendedData = 0;
1218 FIXME("(%p) Unhandled query type %d\n",This , Type);
1220 TRACE("(%p) : Created Query %p\n", This, object);
1221 return WINED3D_OK;
1224 /*****************************************************************************
1225 * IWineD3DDeviceImpl_SetupFullscreenWindow
1227 * Helper function that modifies a HWND's Style and ExStyle for proper
1228 * fullscreen use.
1230 * Params:
1231 * iface: Pointer to the IWineD3DDevice interface
1232 * window: Window to setup
1234 *****************************************************************************/
1235 static LONG fullscreen_style(LONG orig_style) {
1236 LONG style = orig_style;
1237 style &= ~WS_CAPTION;
1238 style &= ~WS_THICKFRAME;
1240 /* Make sure the window is managed, otherwise we won't get keyboard input */
1241 style |= WS_POPUP | WS_SYSMENU;
1243 return style;
1246 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1247 LONG exStyle = orig_exStyle;
1249 /* Filter out window decorations */
1250 exStyle &= ~WS_EX_WINDOWEDGE;
1251 exStyle &= ~WS_EX_CLIENTEDGE;
1253 return exStyle;
1256 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1257 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1259 LONG style, exStyle;
1260 /* Don't do anything if an original style is stored.
1261 * That shouldn't happen
1263 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1264 if (This->style || This->exStyle) {
1265 ERR("(%p): Want to change the window parameters of HWND %p, but "
1266 "another style is stored for restoration afterwards\n", This, window);
1269 /* Get the parameters and save them */
1270 style = GetWindowLongW(window, GWL_STYLE);
1271 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1272 This->style = style;
1273 This->exStyle = exStyle;
1275 style = fullscreen_style(style);
1276 exStyle = fullscreen_exStyle(exStyle);
1278 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1279 This->style, This->exStyle, style, exStyle);
1281 SetWindowLongW(window, GWL_STYLE, style);
1282 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1284 /* Inform the window about the update. */
1285 SetWindowPos(window, HWND_TOP, 0, 0,
1286 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1289 /*****************************************************************************
1290 * IWineD3DDeviceImpl_RestoreWindow
1292 * Helper function that restores a windows' properties when taking it out
1293 * of fullscreen mode
1295 * Params:
1296 * iface: Pointer to the IWineD3DDevice interface
1297 * window: Window to setup
1299 *****************************************************************************/
1300 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1301 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1302 LONG style, exStyle;
1304 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1305 * switch, do nothing
1307 if (!This->style && !This->exStyle) return;
1309 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1310 This, window, This->style, This->exStyle);
1312 style = GetWindowLongW(window, GWL_STYLE);
1313 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1315 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1316 * Some applications change it before calling Reset() when switching between windowed and
1317 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1319 if(style == fullscreen_style(This->style) &&
1320 exStyle == fullscreen_style(This->exStyle)) {
1321 SetWindowLongW(window, GWL_STYLE, This->style);
1322 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1325 /* Delete the old values */
1326 This->style = 0;
1327 This->exStyle = 0;
1329 /* Inform the window about the update */
1330 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1331 0, 0, 0, 0, /* Pos, Size, ignored */
1332 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1335 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1336 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1337 WINED3DPRESENT_PARAMETERS *pPresentationParameters, IWineD3DSwapChain **ppSwapChain,
1338 IUnknown *parent, WINED3DSURFTYPE surface_type)
1340 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1342 HDC hDc;
1343 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1344 HRESULT hr;
1345 IUnknown *bufferParent;
1346 BOOL displaymode_set = FALSE;
1347 WINED3DDISPLAYMODE Mode;
1348 const struct GlPixelFormatDesc *format_desc;
1350 TRACE("(%p) : Created Additional Swap Chain\n", This);
1352 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1353 * does a device hold a reference to a swap chain giving them a lifetime of the device
1354 * or does the swap chain notify the device of its destruction.
1355 *******************************/
1357 /* Check the params */
1358 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1359 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1360 return WINED3DERR_INVALIDCALL;
1361 } else if (pPresentationParameters->BackBufferCount > 1) {
1362 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");
1365 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1366 if(!object)
1368 ERR("Out of memory\n");
1369 *ppSwapChain = NULL;
1370 return WINED3DERR_OUTOFVIDEOMEMORY;
1373 switch(surface_type) {
1374 case SURFACE_GDI:
1375 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1376 break;
1377 case SURFACE_OPENGL:
1378 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1379 break;
1380 case SURFACE_UNKNOWN:
1381 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1382 HeapFree(GetProcessHeap(), 0, object);
1383 return WINED3DERR_INVALIDCALL;
1385 object->wineD3DDevice = This;
1386 object->parent = parent;
1387 object->ref = 1;
1389 *ppSwapChain = (IWineD3DSwapChain *)object;
1391 /*********************
1392 * Lookup the window Handle and the relating X window handle
1393 ********************/
1395 /* Setup hwnd we are using, plus which display this equates to */
1396 object->win_handle = pPresentationParameters->hDeviceWindow;
1397 if (!object->win_handle) {
1398 object->win_handle = This->createParms.hFocusWindow;
1400 if(!pPresentationParameters->Windowed && object->win_handle) {
1401 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1402 pPresentationParameters->BackBufferWidth,
1403 pPresentationParameters->BackBufferHeight);
1406 hDc = GetDC(object->win_handle);
1407 TRACE("Using hDc %p\n", hDc);
1409 if (NULL == hDc) {
1410 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1411 return WINED3DERR_NOTAVAILABLE;
1414 /* Get info on the current display setup */
1415 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1416 object->orig_width = Mode.Width;
1417 object->orig_height = Mode.Height;
1418 object->orig_fmt = Mode.Format;
1419 format_desc = getFormatDescEntry(Mode.Format, &GLINFO_LOCATION);
1421 if (pPresentationParameters->Windowed &&
1422 ((pPresentationParameters->BackBufferWidth == 0) ||
1423 (pPresentationParameters->BackBufferHeight == 0) ||
1424 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1426 RECT Rect;
1427 GetClientRect(object->win_handle, &Rect);
1429 if (pPresentationParameters->BackBufferWidth == 0) {
1430 pPresentationParameters->BackBufferWidth = Rect.right;
1431 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1433 if (pPresentationParameters->BackBufferHeight == 0) {
1434 pPresentationParameters->BackBufferHeight = Rect.bottom;
1435 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1437 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1438 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1439 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1443 /* Put the correct figures in the presentation parameters */
1444 TRACE("Copying across presentation parameters\n");
1445 object->presentParms = *pPresentationParameters;
1447 TRACE("calling rendertarget CB\n");
1448 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1449 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1450 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1451 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->frontBuffer);
1452 if (SUCCEEDED(hr)) {
1453 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1454 ((IWineD3DSurfaceImpl *)object->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
1455 if(surface_type == SURFACE_OPENGL) {
1456 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1458 } else {
1459 ERR("Failed to create the front buffer\n");
1460 goto error;
1463 /*********************
1464 * Windowed / Fullscreen
1465 *******************/
1468 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1469 * so we should really check to see if there is a fullscreen swapchain already
1470 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1471 **************************************/
1473 if (!pPresentationParameters->Windowed) {
1474 WINED3DDISPLAYMODE mode;
1477 /* Change the display settings */
1478 mode.Width = pPresentationParameters->BackBufferWidth;
1479 mode.Height = pPresentationParameters->BackBufferHeight;
1480 mode.Format = pPresentationParameters->BackBufferFormat;
1481 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1483 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1484 displaymode_set = TRUE;
1488 * Create an opengl context for the display visual
1489 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1490 * use different properties after that point in time. FIXME: How to handle when requested format
1491 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1492 * it chooses is identical to the one already being used!
1493 **********************************/
1494 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1496 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1497 if(!object->context) {
1498 ERR("Failed to create the context array\n");
1499 hr = E_OUTOFMEMORY;
1500 goto error;
1502 object->num_contexts = 1;
1504 if(surface_type == SURFACE_OPENGL) {
1505 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1506 if (!object->context[0]) {
1507 ERR("Failed to create a new context\n");
1508 hr = WINED3DERR_NOTAVAILABLE;
1509 goto error;
1510 } else {
1511 TRACE("Context created (HWND=%p, glContext=%p)\n",
1512 object->win_handle, object->context[0]->glCtx);
1516 /*********************
1517 * Create the back, front and stencil buffers
1518 *******************/
1519 if(object->presentParms.BackBufferCount > 0) {
1520 UINT i;
1522 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1523 if(!object->backBuffer) {
1524 ERR("Out of memory\n");
1525 hr = E_OUTOFMEMORY;
1526 goto error;
1529 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1530 TRACE("calling rendertarget CB\n");
1531 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1532 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1533 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1534 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->backBuffer[i]);
1535 if(SUCCEEDED(hr)) {
1536 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1537 ((IWineD3DSurfaceImpl *)object->backBuffer[i])->Flags |= SFLAG_SWAPCHAIN;
1538 } else {
1539 ERR("Cannot create new back buffer\n");
1540 goto error;
1542 if(surface_type == SURFACE_OPENGL) {
1543 ENTER_GL();
1544 glDrawBuffer(GL_BACK);
1545 checkGLcall("glDrawBuffer(GL_BACK)");
1546 LEAVE_GL();
1549 } else {
1550 object->backBuffer = NULL;
1552 /* Single buffering - draw to front buffer */
1553 if(surface_type == SURFACE_OPENGL) {
1554 ENTER_GL();
1555 glDrawBuffer(GL_FRONT);
1556 checkGLcall("glDrawBuffer(GL_FRONT)");
1557 LEAVE_GL();
1561 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1562 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1563 TRACE("Creating depth stencil buffer\n");
1564 if (This->auto_depth_stencil_buffer == NULL ) {
1565 hr = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent, parent,
1566 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1567 object->presentParms.AutoDepthStencilFormat, object->presentParms.MultiSampleType,
1568 object->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */,
1569 &This->auto_depth_stencil_buffer);
1570 if (SUCCEEDED(hr)) {
1571 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1572 } else {
1573 ERR("Failed to create the auto depth stencil\n");
1574 goto error;
1579 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1581 TRACE("Created swapchain %p\n", object);
1582 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1583 return WINED3D_OK;
1585 error:
1586 if (displaymode_set) {
1587 DEVMODEW devmode;
1588 RECT clip_rc;
1590 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1591 ClipCursor(NULL);
1593 /* Change the display settings */
1594 memset(&devmode, 0, sizeof(devmode));
1595 devmode.dmSize = sizeof(devmode);
1596 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1597 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1598 devmode.dmPelsWidth = object->orig_width;
1599 devmode.dmPelsHeight = object->orig_height;
1600 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1603 if (object->backBuffer) {
1604 UINT i;
1605 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1606 if(object->backBuffer[i]) {
1607 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1608 IUnknown_Release(bufferParent); /* once for the get parent */
1609 if (IUnknown_Release(bufferParent) > 0) {
1610 FIXME("(%p) Something's still holding the back buffer\n",This);
1614 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1615 object->backBuffer = NULL;
1617 if(object->context && object->context[0])
1618 DestroyContext(This, object->context[0]);
1619 if(object->frontBuffer) {
1620 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1621 IUnknown_Release(bufferParent); /* once for the get parent */
1622 if (IUnknown_Release(bufferParent) > 0) {
1623 FIXME("(%p) Something's still holding the front buffer\n",This);
1626 HeapFree(GetProcessHeap(), 0, object);
1627 return hr;
1630 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1631 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1632 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1633 TRACE("(%p)\n", This);
1635 return This->NumberOfSwapChains;
1638 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1639 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1640 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1642 if(iSwapChain < This->NumberOfSwapChains) {
1643 *pSwapChain = This->swapchains[iSwapChain];
1644 IWineD3DSwapChain_AddRef(*pSwapChain);
1645 TRACE("(%p) returning %p\n", This, *pSwapChain);
1646 return WINED3D_OK;
1647 } else {
1648 TRACE("Swapchain out of range\n");
1649 *pSwapChain = NULL;
1650 return WINED3DERR_INVALIDCALL;
1654 /*****
1655 * Vertex Declaration
1656 *****/
1657 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1658 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1659 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1660 IWineD3DVertexDeclarationImpl *object = NULL;
1661 HRESULT hr = WINED3D_OK;
1663 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1664 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1666 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1667 if(!object)
1669 ERR("Out of memory\n");
1670 *ppVertexDeclaration = NULL;
1671 return WINED3DERR_OUTOFVIDEOMEMORY;
1674 object->lpVtbl = &IWineD3DVertexDeclaration_Vtbl;
1675 object->wineD3DDevice = This;
1676 object->parent = parent;
1677 object->ref = 1;
1679 *ppVertexDeclaration = (IWineD3DVertexDeclaration *)object;
1681 hr = vertexdeclaration_init(object, elements, element_count);
1683 if(FAILED(hr)) {
1684 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
1685 *ppVertexDeclaration = NULL;
1688 return hr;
1691 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1692 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1694 unsigned int idx, idx2;
1695 unsigned int offset;
1696 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1697 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1698 BOOL has_blend_idx = has_blend &&
1699 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1700 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1701 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1702 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1703 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1704 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1705 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1707 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1708 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1709 WINED3DVERTEXELEMENT *elements = NULL;
1711 unsigned int size;
1712 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1713 if (has_blend_idx) num_blends--;
1715 /* Compute declaration size */
1716 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1717 has_psize + has_diffuse + has_specular + num_textures;
1719 /* convert the declaration */
1720 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1721 if (!elements) return ~0U;
1723 idx = 0;
1724 if (has_pos) {
1725 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1726 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1727 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
1729 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1730 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1731 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1733 else {
1734 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1735 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1737 elements[idx].usage_idx = 0;
1738 idx++;
1740 if (has_blend && (num_blends > 0)) {
1741 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1742 elements[idx].format = WINED3DFMT_A8R8G8B8;
1743 else {
1744 switch(num_blends) {
1745 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
1746 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
1747 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
1748 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
1749 default:
1750 ERR("Unexpected amount of blend values: %u\n", num_blends);
1753 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1754 elements[idx].usage_idx = 0;
1755 idx++;
1757 if (has_blend_idx) {
1758 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1759 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1760 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
1761 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1762 elements[idx].format = WINED3DFMT_A8R8G8B8;
1763 else
1764 elements[idx].format = WINED3DFMT_R32_FLOAT;
1765 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
1766 elements[idx].usage_idx = 0;
1767 idx++;
1769 if (has_normal) {
1770 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1771 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
1772 elements[idx].usage_idx = 0;
1773 idx++;
1775 if (has_psize) {
1776 elements[idx].format = WINED3DFMT_R32_FLOAT;
1777 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
1778 elements[idx].usage_idx = 0;
1779 idx++;
1781 if (has_diffuse) {
1782 elements[idx].format = WINED3DFMT_A8R8G8B8;
1783 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1784 elements[idx].usage_idx = 0;
1785 idx++;
1787 if (has_specular) {
1788 elements[idx].format = WINED3DFMT_A8R8G8B8;
1789 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1790 elements[idx].usage_idx = 1;
1791 idx++;
1793 for (idx2 = 0; idx2 < num_textures; idx2++) {
1794 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1795 switch (numcoords) {
1796 case WINED3DFVF_TEXTUREFORMAT1:
1797 elements[idx].format = WINED3DFMT_R32_FLOAT;
1798 break;
1799 case WINED3DFVF_TEXTUREFORMAT2:
1800 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
1801 break;
1802 case WINED3DFVF_TEXTUREFORMAT3:
1803 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1804 break;
1805 case WINED3DFVF_TEXTUREFORMAT4:
1806 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1807 break;
1809 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
1810 elements[idx].usage_idx = idx2;
1811 idx++;
1814 /* Now compute offsets, and initialize the rest of the fields */
1815 for (idx = 0, offset = 0; idx < size; ++idx)
1817 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
1818 elements[idx].input_slot = 0;
1819 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1820 elements[idx].offset = offset;
1821 offset += format_desc->component_count * format_desc->component_size;
1824 *ppVertexElements = elements;
1825 return size;
1828 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1829 WINED3DVERTEXELEMENT* elements = NULL;
1830 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1831 unsigned int size;
1832 DWORD hr;
1834 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1835 if (size == ~0U) return WINED3DERR_OUTOFVIDEOMEMORY;
1837 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1838 HeapFree(GetProcessHeap(), 0, elements);
1839 if (hr != S_OK) return hr;
1841 return WINED3D_OK;
1844 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1845 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1846 IWineD3DVertexShader **ppVertexShader, IUnknown *parent)
1848 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1849 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1850 HRESULT hr = WINED3D_OK;
1852 if (!pFunction) return WINED3DERR_INVALIDCALL;
1854 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1855 if (!object)
1857 ERR("Out of memory\n");
1858 *ppVertexShader = NULL;
1859 return WINED3DERR_OUTOFVIDEOMEMORY;
1862 object->lpVtbl = &IWineD3DVertexShader_Vtbl;
1863 object->parent = parent;
1864 shader_init(&object->baseShader, iface);
1865 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1866 *ppVertexShader = (IWineD3DVertexShader *)object;
1868 TRACE("(%p) : Created vertex shader %p\n", This, *ppVertexShader);
1870 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction, output_signature);
1871 if (FAILED(hr))
1873 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
1874 IWineD3DVertexShader_Release(*ppVertexShader);
1875 *ppVertexShader = NULL;
1876 return hr;
1879 return hr;
1882 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1883 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1884 IWineD3DPixelShader **ppPixelShader, IUnknown *parent)
1886 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1887 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1888 HRESULT hr = WINED3D_OK;
1890 if (!pFunction) return WINED3DERR_INVALIDCALL;
1892 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1893 if (!object)
1895 ERR("Out of memory\n");
1896 *ppPixelShader = NULL;
1897 return WINED3DERR_OUTOFVIDEOMEMORY;
1900 object->lpVtbl = &IWineD3DPixelShader_Vtbl;
1901 object->parent = parent;
1902 shader_init(&object->baseShader, iface);
1903 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1904 *ppPixelShader = (IWineD3DPixelShader *)object;
1906 TRACE("(%p) : Created pixel shader %p\n", This, *ppPixelShader);
1908 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction, output_signature);
1909 if (FAILED(hr))
1911 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
1912 IWineD3DPixelShader_Release(*ppPixelShader);
1913 *ppPixelShader = NULL;
1914 return hr;
1917 return hr;
1920 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1921 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1924 IWineD3DPaletteImpl *object;
1925 HRESULT hr;
1926 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1928 /* Create the new object */
1929 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1930 if(!object) {
1931 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1932 return E_OUTOFMEMORY;
1935 object->lpVtbl = &IWineD3DPalette_Vtbl;
1936 object->ref = 1;
1937 object->Flags = Flags;
1938 object->parent = Parent;
1939 object->wineD3DDevice = This;
1940 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1941 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1943 if(!object->hpal) {
1944 HeapFree( GetProcessHeap(), 0, object);
1945 return E_OUTOFMEMORY;
1948 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1949 if(FAILED(hr)) {
1950 IWineD3DPalette_Release((IWineD3DPalette *) object);
1951 return hr;
1954 *Palette = (IWineD3DPalette *) object;
1956 return WINED3D_OK;
1959 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1960 HBITMAP hbm;
1961 BITMAP bm;
1962 HRESULT hr;
1963 HDC dcb = NULL, dcs = NULL;
1964 WINEDDCOLORKEY colorkey;
1966 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1967 if(hbm)
1969 GetObjectA(hbm, sizeof(BITMAP), &bm);
1970 dcb = CreateCompatibleDC(NULL);
1971 if(!dcb) goto out;
1972 SelectObject(dcb, hbm);
1974 else
1976 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1977 * couldn't be loaded
1979 memset(&bm, 0, sizeof(bm));
1980 bm.bmWidth = 32;
1981 bm.bmHeight = 32;
1984 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5, TRUE,
1985 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL, NULL);
1986 if(FAILED(hr)) {
1987 ERR("Wine logo requested, but failed to create surface\n");
1988 goto out;
1991 if(dcb) {
1992 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1993 if(FAILED(hr)) goto out;
1994 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1995 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1997 colorkey.dwColorSpaceLowValue = 0;
1998 colorkey.dwColorSpaceHighValue = 0;
1999 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2000 } else {
2001 /* Fill the surface with a white color to show that wined3d is there */
2002 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2005 out:
2006 if(dcb) {
2007 DeleteDC(dcb);
2009 if(hbm) {
2010 DeleteObject(hbm);
2012 return;
2015 /* Context activation is done by the caller. */
2016 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2017 unsigned int i;
2018 /* Under DirectX you can have texture stage operations even if no texture is
2019 bound, whereas opengl will only do texture operations when a valid texture is
2020 bound. We emulate this by creating dummy textures and binding them to each
2021 texture stage, but disable all stages by default. Hence if a stage is enabled
2022 then the default texture will kick in until replaced by a SetTexture call */
2023 ENTER_GL();
2025 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2026 /* The dummy texture does not have client storage backing */
2027 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2028 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2030 for (i = 0; i < GL_LIMITS(textures); i++) {
2031 GLubyte white = 255;
2033 /* Make appropriate texture active */
2034 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2035 checkGLcall("glActiveTextureARB");
2037 /* Generate an opengl texture name */
2038 glGenTextures(1, &This->dummyTextureName[i]);
2039 checkGLcall("glGenTextures");
2040 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2042 /* Generate a dummy 2d texture (not using 1d because they cause many
2043 * DRI drivers fall back to sw) */
2044 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2045 checkGLcall("glBindTexture");
2047 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2048 checkGLcall("glTexImage2D");
2050 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2051 /* Reenable because if supported it is enabled by default */
2052 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2053 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2056 LEAVE_GL();
2059 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
2060 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2062 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2063 IWineD3DSwapChainImpl *swapchain = NULL;
2064 HRESULT hr;
2065 DWORD state;
2066 unsigned int i;
2068 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
2070 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2071 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2073 /* TODO: Test if OpenGL is compiled in and loaded */
2075 TRACE("(%p) : Creating stateblock\n", This);
2076 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2077 hr = IWineD3DDevice_CreateStateBlock(iface,
2078 WINED3DSBT_INIT,
2079 (IWineD3DStateBlock **)&This->stateBlock,
2080 NULL);
2081 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2082 WARN("Failed to create stateblock\n");
2083 goto err_out;
2085 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2086 This->updateStateBlock = This->stateBlock;
2087 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2089 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2090 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2092 This->NumberOfPalettes = 1;
2093 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2094 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2095 ERR("Out of memory!\n");
2096 goto err_out;
2098 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2099 if(!This->palettes[0]) {
2100 ERR("Out of memory!\n");
2101 goto err_out;
2103 for (i = 0; i < 256; ++i) {
2104 This->palettes[0][i].peRed = 0xFF;
2105 This->palettes[0][i].peGreen = 0xFF;
2106 This->palettes[0][i].peBlue = 0xFF;
2107 This->palettes[0][i].peFlags = 0xFF;
2109 This->currentPalette = 0;
2111 /* Initialize the texture unit mapping to a 1:1 mapping */
2112 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2113 if (state < GL_LIMITS(fragment_samplers)) {
2114 This->texUnitMap[state] = state;
2115 This->rev_tex_unit_map[state] = state;
2116 } else {
2117 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
2118 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
2122 /* Setup the implicit swapchain. This also initializes a context. */
2123 TRACE("Creating implicit swapchain\n");
2124 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2125 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2126 if (FAILED(hr))
2128 WARN("Failed to create implicit swapchain\n");
2129 goto err_out;
2132 This->NumberOfSwapChains = 1;
2133 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2134 if(!This->swapchains) {
2135 ERR("Out of memory!\n");
2136 goto err_out;
2138 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2140 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2141 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2142 This->render_targets[0] = swapchain->backBuffer[0];
2144 else {
2145 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2146 This->render_targets[0] = swapchain->frontBuffer;
2148 IWineD3DSurface_AddRef(This->render_targets[0]);
2150 /* Depth Stencil support */
2151 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2152 if (NULL != This->stencilBufferTarget) {
2153 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2156 hr = This->shader_backend->shader_alloc_private(iface);
2157 if(FAILED(hr)) {
2158 TRACE("Shader private data couldn't be allocated\n");
2159 goto err_out;
2161 hr = This->frag_pipe->alloc_private(iface);
2162 if(FAILED(hr)) {
2163 TRACE("Fragment pipeline private data couldn't be allocated\n");
2164 goto err_out;
2166 hr = This->blitter->alloc_private(iface);
2167 if(FAILED(hr)) {
2168 TRACE("Blitter private data couldn't be allocated\n");
2169 goto err_out;
2172 /* Set up some starting GL setup */
2174 /* Setup all the devices defaults */
2175 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2176 create_dummy_textures(This);
2178 ENTER_GL();
2180 /* Initialize the current view state */
2181 This->view_ident = 1;
2182 This->contexts[0]->last_was_rhw = 0;
2183 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2184 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2186 switch(wined3d_settings.offscreen_rendering_mode) {
2187 case ORM_FBO:
2188 case ORM_PBUFFER:
2189 This->offscreenBuffer = GL_BACK;
2190 break;
2192 case ORM_BACKBUFFER:
2194 if (context_get_current()->aux_buffers > 0)
2196 TRACE("Using auxilliary buffer for offscreen rendering\n");
2197 This->offscreenBuffer = GL_AUX0;
2198 } else {
2199 TRACE("Using back buffer for offscreen rendering\n");
2200 This->offscreenBuffer = GL_BACK;
2205 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2206 LEAVE_GL();
2208 /* Clear the screen */
2209 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2210 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2211 0x00, 1.0f, 0);
2213 This->d3d_initialized = TRUE;
2215 if(wined3d_settings.logo) {
2216 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2218 This->highest_dirty_ps_const = 0;
2219 This->highest_dirty_vs_const = 0;
2220 return WINED3D_OK;
2222 err_out:
2223 HeapFree(GetProcessHeap(), 0, This->render_targets);
2224 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2225 HeapFree(GetProcessHeap(), 0, This->swapchains);
2226 This->NumberOfSwapChains = 0;
2227 if(This->palettes) {
2228 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2229 HeapFree(GetProcessHeap(), 0, This->palettes);
2231 This->NumberOfPalettes = 0;
2232 if(swapchain) {
2233 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2235 if(This->stateBlock) {
2236 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2237 This->stateBlock = NULL;
2239 if (This->blit_priv) {
2240 This->blitter->free_private(iface);
2242 if (This->fragment_priv) {
2243 This->frag_pipe->free_private(iface);
2245 if (This->shader_priv) {
2246 This->shader_backend->shader_free_private(iface);
2248 return hr;
2251 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2252 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2254 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2255 IWineD3DSwapChainImpl *swapchain = NULL;
2256 HRESULT hr;
2258 /* Setup the implicit swapchain */
2259 TRACE("Creating implicit swapchain\n");
2260 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2261 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2262 if (FAILED(hr))
2264 WARN("Failed to create implicit swapchain\n");
2265 goto err_out;
2268 This->NumberOfSwapChains = 1;
2269 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2270 if(!This->swapchains) {
2271 ERR("Out of memory!\n");
2272 goto err_out;
2274 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2275 return WINED3D_OK;
2277 err_out:
2278 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2279 return hr;
2282 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2284 IWineD3DResource_UnLoad(resource);
2285 IWineD3DResource_Release(resource);
2286 return WINED3D_OK;
2289 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2290 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2291 int sampler;
2292 UINT i;
2293 TRACE("(%p)\n", This);
2295 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2297 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2298 * it was created. Thus make sure a context is active for the glDelete* calls
2300 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
2302 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2304 /* Unload resources */
2305 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2307 TRACE("Deleting high order patches\n");
2308 for(i = 0; i < PATCHMAP_SIZE; i++) {
2309 struct list *e1, *e2;
2310 struct WineD3DRectPatch *patch;
2311 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2312 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2313 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2317 /* Delete the palette conversion shader if it is around */
2318 if(This->paletteConversionShader) {
2319 ENTER_GL();
2320 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2321 LEAVE_GL();
2322 This->paletteConversionShader = 0;
2325 /* Delete the pbuffer context if there is any */
2326 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2328 /* Delete the mouse cursor texture */
2329 if(This->cursorTexture) {
2330 ENTER_GL();
2331 glDeleteTextures(1, &This->cursorTexture);
2332 LEAVE_GL();
2333 This->cursorTexture = 0;
2336 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2337 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2339 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2340 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2343 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2344 * private data, it might contain opengl pointers
2346 if(This->depth_blt_texture) {
2347 ENTER_GL();
2348 glDeleteTextures(1, &This->depth_blt_texture);
2349 LEAVE_GL();
2350 This->depth_blt_texture = 0;
2352 if (This->depth_blt_rb) {
2353 ENTER_GL();
2354 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2355 LEAVE_GL();
2356 This->depth_blt_rb = 0;
2357 This->depth_blt_rb_w = 0;
2358 This->depth_blt_rb_h = 0;
2361 /* Release the update stateblock */
2362 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2363 if(This->updateStateBlock != This->stateBlock)
2364 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2366 This->updateStateBlock = NULL;
2368 { /* because were not doing proper internal refcounts releasing the primary state block
2369 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2370 to set this->stateBlock = NULL; first */
2371 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2372 This->stateBlock = NULL;
2374 /* Release the stateblock */
2375 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2376 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2380 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2381 This->blitter->free_private(iface);
2382 This->frag_pipe->free_private(iface);
2383 This->shader_backend->shader_free_private(iface);
2385 /* Release the buffers (with sanity checks)*/
2386 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2387 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2388 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2389 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2391 This->stencilBufferTarget = NULL;
2393 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2394 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2395 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2397 TRACE("Setting rendertarget to NULL\n");
2398 This->render_targets[0] = NULL;
2400 if (This->auto_depth_stencil_buffer) {
2401 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2402 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2404 This->auto_depth_stencil_buffer = NULL;
2407 for(i=0; i < This->NumberOfSwapChains; i++) {
2408 TRACE("Releasing the implicit swapchain %d\n", i);
2409 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2410 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2414 HeapFree(GetProcessHeap(), 0, This->swapchains);
2415 This->swapchains = NULL;
2416 This->NumberOfSwapChains = 0;
2418 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2419 HeapFree(GetProcessHeap(), 0, This->palettes);
2420 This->palettes = NULL;
2421 This->NumberOfPalettes = 0;
2423 HeapFree(GetProcessHeap(), 0, This->render_targets);
2424 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2425 This->render_targets = NULL;
2426 This->draw_buffers = NULL;
2428 This->d3d_initialized = FALSE;
2429 return WINED3D_OK;
2432 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2433 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2434 unsigned int i;
2436 for(i=0; i < This->NumberOfSwapChains; i++) {
2437 TRACE("Releasing the implicit swapchain %d\n", i);
2438 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2439 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2443 HeapFree(GetProcessHeap(), 0, This->swapchains);
2444 This->swapchains = NULL;
2445 This->NumberOfSwapChains = 0;
2446 return WINED3D_OK;
2449 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2450 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2451 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2453 * There is no way to deactivate thread safety once it is enabled.
2455 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2456 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2458 /*For now just store the flag(needed in case of ddraw) */
2459 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2461 return;
2464 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2465 const WINED3DDISPLAYMODE* pMode) {
2466 DEVMODEW devmode;
2467 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2468 LONG ret;
2469 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &GLINFO_LOCATION);
2470 RECT clip_rc;
2472 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2474 /* Resize the screen even without a window:
2475 * The app could have unset it with SetCooperativeLevel, but not called
2476 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2477 * but we don't have any hwnd
2480 memset(&devmode, 0, sizeof(devmode));
2481 devmode.dmSize = sizeof(devmode);
2482 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2483 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2484 devmode.dmPelsWidth = pMode->Width;
2485 devmode.dmPelsHeight = pMode->Height;
2487 devmode.dmDisplayFrequency = pMode->RefreshRate;
2488 if (pMode->RefreshRate != 0) {
2489 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2492 /* Only change the mode if necessary */
2493 if( (This->ddraw_width == pMode->Width) &&
2494 (This->ddraw_height == pMode->Height) &&
2495 (This->ddraw_format == pMode->Format) &&
2496 (pMode->RefreshRate == 0) ) {
2497 return WINED3D_OK;
2500 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2501 if (ret != DISP_CHANGE_SUCCESSFUL) {
2502 if(devmode.dmDisplayFrequency != 0) {
2503 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2504 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2505 devmode.dmDisplayFrequency = 0;
2506 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2508 if(ret != DISP_CHANGE_SUCCESSFUL) {
2509 return WINED3DERR_NOTAVAILABLE;
2513 /* Store the new values */
2514 This->ddraw_width = pMode->Width;
2515 This->ddraw_height = pMode->Height;
2516 This->ddraw_format = pMode->Format;
2518 /* And finally clip mouse to our screen */
2519 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2520 ClipCursor(&clip_rc);
2522 return WINED3D_OK;
2525 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2526 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2527 *ppD3D= This->wineD3D;
2528 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2529 IWineD3D_AddRef(*ppD3D);
2530 return WINED3D_OK;
2533 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2534 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2536 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2537 (This->adapter->TextureRam/(1024*1024)),
2538 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2539 /* return simulated texture memory left */
2540 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2543 /*****
2544 * Get / Set Stream Source
2545 *****/
2546 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2547 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2549 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2550 IWineD3DBuffer *oldSrc;
2552 if (StreamNumber >= MAX_STREAMS) {
2553 WARN("Stream out of range %d\n", StreamNumber);
2554 return WINED3DERR_INVALIDCALL;
2555 } else if(OffsetInBytes & 0x3) {
2556 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2557 return WINED3DERR_INVALIDCALL;
2560 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2561 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2563 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2565 if(oldSrc == pStreamData &&
2566 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2567 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2568 TRACE("Application is setting the old values over, nothing to do\n");
2569 return WINED3D_OK;
2572 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2573 if (pStreamData) {
2574 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2575 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2578 /* Handle recording of state blocks */
2579 if (This->isRecordingState) {
2580 TRACE("Recording... not performing anything\n");
2581 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2582 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2583 return WINED3D_OK;
2586 if (pStreamData != NULL) {
2587 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2588 IWineD3DBuffer_AddRef(pStreamData);
2590 if (oldSrc != NULL) {
2591 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2592 IWineD3DBuffer_Release(oldSrc);
2595 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2597 return WINED3D_OK;
2600 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2601 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2603 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2605 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2606 This->stateBlock->streamSource[StreamNumber],
2607 This->stateBlock->streamOffset[StreamNumber],
2608 This->stateBlock->streamStride[StreamNumber]);
2610 if (StreamNumber >= MAX_STREAMS) {
2611 WARN("Stream out of range %d\n", StreamNumber);
2612 return WINED3DERR_INVALIDCALL;
2614 *pStream = This->stateBlock->streamSource[StreamNumber];
2615 *pStride = This->stateBlock->streamStride[StreamNumber];
2616 if (pOffset) {
2617 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2620 if (*pStream != NULL) {
2621 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2623 return WINED3D_OK;
2626 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2627 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2628 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2629 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2631 /* Verify input at least in d3d9 this is invalid*/
2632 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2633 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2634 return WINED3DERR_INVALIDCALL;
2636 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2637 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2638 return WINED3DERR_INVALIDCALL;
2640 if( Divider == 0 ){
2641 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2642 return WINED3DERR_INVALIDCALL;
2645 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2646 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2648 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2649 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2651 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2652 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2653 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2656 return WINED3D_OK;
2659 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2660 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2662 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2663 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2665 TRACE("(%p) : returning %d\n", This, *Divider);
2667 return WINED3D_OK;
2670 /*****
2671 * Get / Set & Multiply Transform
2672 *****/
2673 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2676 /* Most of this routine, comments included copied from ddraw tree initially: */
2677 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2679 /* Handle recording of state blocks */
2680 if (This->isRecordingState) {
2681 TRACE("Recording... not performing anything\n");
2682 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2683 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2684 return WINED3D_OK;
2688 * If the new matrix is the same as the current one,
2689 * we cut off any further processing. this seems to be a reasonable
2690 * optimization because as was noticed, some apps (warcraft3 for example)
2691 * tend towards setting the same matrix repeatedly for some reason.
2693 * From here on we assume that the new matrix is different, wherever it matters.
2695 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2696 TRACE("The app is setting the same matrix over again\n");
2697 return WINED3D_OK;
2698 } else {
2699 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2703 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2704 where ViewMat = Camera space, WorldMat = world space.
2706 In OpenGL, camera and world space is combined into GL_MODELVIEW
2707 matrix. The Projection matrix stay projection matrix.
2710 /* Capture the times we can just ignore the change for now */
2711 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2712 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2713 /* Handled by the state manager */
2716 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2717 return WINED3D_OK;
2720 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2721 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2722 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2723 *pMatrix = This->stateBlock->transforms[State];
2724 return WINED3D_OK;
2727 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2728 const WINED3DMATRIX *mat = NULL;
2729 WINED3DMATRIX temp;
2731 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2732 * below means it will be recorded in a state block change, but it
2733 * works regardless where it is recorded.
2734 * If this is found to be wrong, change to StateBlock.
2736 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2737 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2739 if (State <= HIGHEST_TRANSFORMSTATE)
2741 mat = &This->updateStateBlock->transforms[State];
2742 } else {
2743 FIXME("Unhandled transform state!!\n");
2746 multiply_matrix(&temp, mat, pMatrix);
2748 /* Apply change via set transform - will reapply to eg. lights this way */
2749 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2752 /*****
2753 * Get / Set Light
2754 *****/
2755 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2756 you can reference any indexes you want as long as that number max are enabled at any
2757 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2758 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2759 but when recording, just build a chain pretty much of commands to be replayed. */
2761 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2762 float rho;
2763 PLIGHTINFOEL *object = NULL;
2764 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2765 struct list *e;
2767 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2768 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2770 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2771 * the gl driver.
2773 if(!pLight) {
2774 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2775 return WINED3DERR_INVALIDCALL;
2778 switch(pLight->Type) {
2779 case WINED3DLIGHT_POINT:
2780 case WINED3DLIGHT_SPOT:
2781 case WINED3DLIGHT_PARALLELPOINT:
2782 case WINED3DLIGHT_GLSPOT:
2783 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2784 * most wanted
2786 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2788 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2789 return WINED3DERR_INVALIDCALL;
2791 break;
2793 case WINED3DLIGHT_DIRECTIONAL:
2794 /* Ignores attenuation */
2795 break;
2797 default:
2798 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2799 return WINED3DERR_INVALIDCALL;
2802 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2803 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2804 if(object->OriginalIndex == Index) break;
2805 object = NULL;
2808 if(!object) {
2809 TRACE("Adding new light\n");
2810 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2811 if(!object) {
2812 ERR("Out of memory error when allocating a light\n");
2813 return E_OUTOFMEMORY;
2815 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2816 object->glIndex = -1;
2817 object->OriginalIndex = Index;
2818 object->changed = TRUE;
2821 /* Initialize the object */
2822 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,
2823 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2824 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2825 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2826 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2827 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2828 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2830 /* Save away the information */
2831 object->OriginalParms = *pLight;
2833 switch (pLight->Type) {
2834 case WINED3DLIGHT_POINT:
2835 /* Position */
2836 object->lightPosn[0] = pLight->Position.x;
2837 object->lightPosn[1] = pLight->Position.y;
2838 object->lightPosn[2] = pLight->Position.z;
2839 object->lightPosn[3] = 1.0f;
2840 object->cutoff = 180.0f;
2841 /* FIXME: Range */
2842 break;
2844 case WINED3DLIGHT_DIRECTIONAL:
2845 /* Direction */
2846 object->lightPosn[0] = -pLight->Direction.x;
2847 object->lightPosn[1] = -pLight->Direction.y;
2848 object->lightPosn[2] = -pLight->Direction.z;
2849 object->lightPosn[3] = 0.0f;
2850 object->exponent = 0.0f;
2851 object->cutoff = 180.0f;
2852 break;
2854 case WINED3DLIGHT_SPOT:
2855 /* Position */
2856 object->lightPosn[0] = pLight->Position.x;
2857 object->lightPosn[1] = pLight->Position.y;
2858 object->lightPosn[2] = pLight->Position.z;
2859 object->lightPosn[3] = 1.0f;
2861 /* Direction */
2862 object->lightDirn[0] = pLight->Direction.x;
2863 object->lightDirn[1] = pLight->Direction.y;
2864 object->lightDirn[2] = pLight->Direction.z;
2865 object->lightDirn[3] = 1.0f;
2868 * opengl-ish and d3d-ish spot lights use too different models for the
2869 * light "intensity" as a function of the angle towards the main light direction,
2870 * so we only can approximate very roughly.
2871 * however spot lights are rather rarely used in games (if ever used at all).
2872 * furthermore if still used, probably nobody pays attention to such details.
2874 if (pLight->Falloff == 0) {
2875 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2876 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2877 * will always be 1.0 for both of them, and we don't have to care for the
2878 * rest of the rather complex calculation
2880 object->exponent = 0.0f;
2881 } else {
2882 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2883 if (rho < 0.0001f) rho = 0.0001f;
2884 object->exponent = -0.3f/logf(cosf(rho/2));
2886 if (object->exponent > 128.0f)
2888 object->exponent = 128.0f;
2890 object->cutoff = pLight->Phi*90/M_PI;
2892 /* FIXME: Range */
2893 break;
2895 default:
2896 FIXME("Unrecognized light type %d\n", pLight->Type);
2899 /* Update the live definitions if the light is currently assigned a glIndex */
2900 if (object->glIndex != -1 && !This->isRecordingState) {
2901 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2903 return WINED3D_OK;
2906 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2907 PLIGHTINFOEL *lightInfo = NULL;
2908 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2909 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2910 struct list *e;
2911 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2913 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2914 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2915 if(lightInfo->OriginalIndex == Index) break;
2916 lightInfo = NULL;
2919 if (lightInfo == NULL) {
2920 TRACE("Light information requested but light not defined\n");
2921 return WINED3DERR_INVALIDCALL;
2924 *pLight = lightInfo->OriginalParms;
2925 return WINED3D_OK;
2928 /*****
2929 * Get / Set Light Enable
2930 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2931 *****/
2932 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2933 PLIGHTINFOEL *lightInfo = NULL;
2934 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2935 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2936 struct list *e;
2937 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2939 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2940 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2941 if(lightInfo->OriginalIndex == Index) break;
2942 lightInfo = NULL;
2944 TRACE("Found light: %p\n", lightInfo);
2946 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2947 if (lightInfo == NULL) {
2949 TRACE("Light enabled requested but light not defined, so defining one!\n");
2950 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2952 /* Search for it again! Should be fairly quick as near head of list */
2953 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2954 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2955 if(lightInfo->OriginalIndex == Index) break;
2956 lightInfo = NULL;
2958 if (lightInfo == NULL) {
2959 FIXME("Adding default lights has failed dismally\n");
2960 return WINED3DERR_INVALIDCALL;
2964 lightInfo->enabledChanged = TRUE;
2965 if(!Enable) {
2966 if(lightInfo->glIndex != -1) {
2967 if(!This->isRecordingState) {
2968 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2971 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2972 lightInfo->glIndex = -1;
2973 } else {
2974 TRACE("Light already disabled, nothing to do\n");
2976 lightInfo->enabled = FALSE;
2977 } else {
2978 lightInfo->enabled = TRUE;
2979 if (lightInfo->glIndex != -1) {
2980 /* nop */
2981 TRACE("Nothing to do as light was enabled\n");
2982 } else {
2983 int i;
2984 /* Find a free gl light */
2985 for(i = 0; i < This->maxConcurrentLights; i++) {
2986 if(This->updateStateBlock->activeLights[i] == NULL) {
2987 This->updateStateBlock->activeLights[i] = lightInfo;
2988 lightInfo->glIndex = i;
2989 break;
2992 if(lightInfo->glIndex == -1) {
2993 /* Our tests show that Windows returns D3D_OK in this situation, even with
2994 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2995 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2996 * as well for those lights.
2998 * TODO: Test how this affects rendering
3000 WARN("Too many concurrently active lights\n");
3001 return WINED3D_OK;
3004 /* i == lightInfo->glIndex */
3005 if(!This->isRecordingState) {
3006 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3011 return WINED3D_OK;
3014 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3016 PLIGHTINFOEL *lightInfo = NULL;
3017 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3018 struct list *e;
3019 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3020 TRACE("(%p) : for idx(%d)\n", This, Index);
3022 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3023 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3024 if(lightInfo->OriginalIndex == Index) break;
3025 lightInfo = NULL;
3028 if (lightInfo == NULL) {
3029 TRACE("Light enabled state requested but light not defined\n");
3030 return WINED3DERR_INVALIDCALL;
3032 /* true is 128 according to SetLightEnable */
3033 *pEnable = lightInfo->enabled ? 128 : 0;
3034 return WINED3D_OK;
3037 /*****
3038 * Get / Set Clip Planes
3039 *****/
3040 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3041 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3042 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3044 /* Validate Index */
3045 if (Index >= GL_LIMITS(clipplanes)) {
3046 TRACE("Application has requested clipplane this device doesn't support\n");
3047 return WINED3DERR_INVALIDCALL;
3050 This->updateStateBlock->changed.clipplane |= 1 << Index;
3052 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3053 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3054 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3055 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3056 TRACE("Application is setting old values over, nothing to do\n");
3057 return WINED3D_OK;
3060 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3061 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3062 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3063 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3065 /* Handle recording of state blocks */
3066 if (This->isRecordingState) {
3067 TRACE("Recording... not performing anything\n");
3068 return WINED3D_OK;
3071 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3073 return WINED3D_OK;
3076 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3077 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3078 TRACE("(%p) : for idx %d\n", This, Index);
3080 /* Validate Index */
3081 if (Index >= GL_LIMITS(clipplanes)) {
3082 TRACE("Application has requested clipplane this device doesn't support\n");
3083 return WINED3DERR_INVALIDCALL;
3086 pPlane[0] = This->stateBlock->clipplane[Index][0];
3087 pPlane[1] = This->stateBlock->clipplane[Index][1];
3088 pPlane[2] = This->stateBlock->clipplane[Index][2];
3089 pPlane[3] = This->stateBlock->clipplane[Index][3];
3090 return WINED3D_OK;
3093 /*****
3094 * Get / Set Clip Plane Status
3095 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3096 *****/
3097 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3098 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3099 FIXME("(%p) : stub\n", This);
3100 if (NULL == pClipStatus) {
3101 return WINED3DERR_INVALIDCALL;
3103 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3104 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3105 return WINED3D_OK;
3108 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3109 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3110 FIXME("(%p) : stub\n", This);
3111 if (NULL == pClipStatus) {
3112 return WINED3DERR_INVALIDCALL;
3114 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3115 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3116 return WINED3D_OK;
3119 /*****
3120 * Get / Set Material
3121 *****/
3122 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3123 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3125 This->updateStateBlock->changed.material = TRUE;
3126 This->updateStateBlock->material = *pMaterial;
3128 /* Handle recording of state blocks */
3129 if (This->isRecordingState) {
3130 TRACE("Recording... not performing anything\n");
3131 return WINED3D_OK;
3134 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3135 return WINED3D_OK;
3138 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3140 *pMaterial = This->updateStateBlock->material;
3141 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3142 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3143 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3144 pMaterial->Ambient.b, pMaterial->Ambient.a);
3145 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3146 pMaterial->Specular.b, pMaterial->Specular.a);
3147 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3148 pMaterial->Emissive.b, pMaterial->Emissive.a);
3149 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3151 return WINED3D_OK;
3154 /*****
3155 * Get / Set Indices
3156 *****/
3157 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DBuffer* pIndexData, WINED3DFORMAT fmt) {
3158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3159 IWineD3DBuffer *oldIdxs;
3161 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3162 oldIdxs = This->updateStateBlock->pIndexData;
3164 This->updateStateBlock->changed.indices = TRUE;
3165 This->updateStateBlock->pIndexData = pIndexData;
3166 This->updateStateBlock->IndexFmt = fmt;
3168 /* Handle recording of state blocks */
3169 if (This->isRecordingState) {
3170 TRACE("Recording... not performing anything\n");
3171 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
3172 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
3173 return WINED3D_OK;
3176 if(oldIdxs != pIndexData) {
3177 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3178 if(pIndexData) {
3179 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
3180 IWineD3DBuffer_AddRef(pIndexData);
3182 if(oldIdxs) {
3183 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
3184 IWineD3DBuffer_Release(oldIdxs);
3188 return WINED3D_OK;
3191 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DBuffer** ppIndexData) {
3192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3194 *ppIndexData = This->stateBlock->pIndexData;
3196 /* up ref count on ppindexdata */
3197 if (*ppIndexData) {
3198 IWineD3DBuffer_AddRef(*ppIndexData);
3199 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3200 }else{
3201 TRACE("(%p) No index data set\n", This);
3203 TRACE("Returning %p\n", *ppIndexData);
3205 return WINED3D_OK;
3208 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3209 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3210 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3211 TRACE("(%p)->(%d)\n", This, BaseIndex);
3213 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3214 TRACE("Application is setting the old value over, nothing to do\n");
3215 return WINED3D_OK;
3218 This->updateStateBlock->baseVertexIndex = BaseIndex;
3220 if (This->isRecordingState) {
3221 TRACE("Recording... not performing anything\n");
3222 return WINED3D_OK;
3224 /* The base vertex index affects the stream sources */
3225 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3226 return WINED3D_OK;
3229 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3230 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3231 TRACE("(%p) : base_index %p\n", This, base_index);
3233 *base_index = This->stateBlock->baseVertexIndex;
3235 TRACE("Returning %u\n", *base_index);
3237 return WINED3D_OK;
3240 /*****
3241 * Get / Set Viewports
3242 *****/
3243 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3244 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3246 TRACE("(%p)\n", This);
3247 This->updateStateBlock->changed.viewport = TRUE;
3248 This->updateStateBlock->viewport = *pViewport;
3250 /* Handle recording of state blocks */
3251 if (This->isRecordingState) {
3252 TRACE("Recording... not performing anything\n");
3253 return WINED3D_OK;
3256 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3257 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3259 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3260 return WINED3D_OK;
3264 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3265 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3266 TRACE("(%p)\n", This);
3267 *pViewport = This->stateBlock->viewport;
3268 return WINED3D_OK;
3271 /*****
3272 * Get / Set Render States
3273 * TODO: Verify against dx9 definitions
3274 *****/
3275 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3277 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3278 DWORD oldValue = This->stateBlock->renderState[State];
3280 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3282 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3283 This->updateStateBlock->renderState[State] = Value;
3285 /* Handle recording of state blocks */
3286 if (This->isRecordingState) {
3287 TRACE("Recording... not performing anything\n");
3288 return WINED3D_OK;
3291 /* Compared here and not before the assignment to allow proper stateblock recording */
3292 if(Value == oldValue) {
3293 TRACE("Application is setting the old value over, nothing to do\n");
3294 } else {
3295 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3298 return WINED3D_OK;
3301 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3302 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3303 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3304 *pValue = This->stateBlock->renderState[State];
3305 return WINED3D_OK;
3308 /*****
3309 * Get / Set Sampler States
3310 * TODO: Verify against dx9 definitions
3311 *****/
3313 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3315 DWORD oldValue;
3317 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3318 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3320 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3321 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3324 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3325 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3326 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3329 * SetSampler is designed to allow for more than the standard up to 8 textures
3330 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3331 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3333 * http://developer.nvidia.com/object/General_FAQ.html#t6
3335 * There are two new settings for GForce
3336 * the sampler one:
3337 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3338 * and the texture one:
3339 * GL_MAX_TEXTURE_COORDS_ARB.
3340 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3341 ******************/
3343 oldValue = This->stateBlock->samplerState[Sampler][Type];
3344 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3345 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3347 /* Handle recording of state blocks */
3348 if (This->isRecordingState) {
3349 TRACE("Recording... not performing anything\n");
3350 return WINED3D_OK;
3353 if(oldValue == Value) {
3354 TRACE("Application is setting the old value over, nothing to do\n");
3355 return WINED3D_OK;
3358 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3360 return WINED3D_OK;
3363 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3364 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3366 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3367 This, Sampler, debug_d3dsamplerstate(Type), Type);
3369 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3370 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3373 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3374 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3375 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3377 *Value = This->stateBlock->samplerState[Sampler][Type];
3378 TRACE("(%p) : Returning %#x\n", This, *Value);
3380 return WINED3D_OK;
3383 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3384 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3386 This->updateStateBlock->changed.scissorRect = TRUE;
3387 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3388 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3389 return WINED3D_OK;
3391 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3393 if(This->isRecordingState) {
3394 TRACE("Recording... not performing anything\n");
3395 return WINED3D_OK;
3398 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3400 return WINED3D_OK;
3403 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3404 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3406 *pRect = This->updateStateBlock->scissorRect;
3407 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3408 return WINED3D_OK;
3411 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3413 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3415 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3417 This->updateStateBlock->vertexDecl = pDecl;
3418 This->updateStateBlock->changed.vertexDecl = TRUE;
3420 if (This->isRecordingState) {
3421 TRACE("Recording... not performing anything\n");
3422 return WINED3D_OK;
3423 } else if(pDecl == oldDecl) {
3424 /* Checked after the assignment to allow proper stateblock recording */
3425 TRACE("Application is setting the old declaration over, nothing to do\n");
3426 return WINED3D_OK;
3429 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3430 return WINED3D_OK;
3433 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3434 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3436 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3438 *ppDecl = This->stateBlock->vertexDecl;
3439 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3440 return WINED3D_OK;
3443 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3444 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3445 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3447 This->updateStateBlock->vertexShader = pShader;
3448 This->updateStateBlock->changed.vertexShader = TRUE;
3450 if (This->isRecordingState) {
3451 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3452 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3453 TRACE("Recording... not performing anything\n");
3454 return WINED3D_OK;
3455 } else if(oldShader == pShader) {
3456 /* Checked here to allow proper stateblock recording */
3457 TRACE("App is setting the old shader over, nothing to do\n");
3458 return WINED3D_OK;
3461 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3462 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3463 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3465 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3467 return WINED3D_OK;
3470 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3471 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3473 if (NULL == ppShader) {
3474 return WINED3DERR_INVALIDCALL;
3476 *ppShader = This->stateBlock->vertexShader;
3477 if( NULL != *ppShader)
3478 IWineD3DVertexShader_AddRef(*ppShader);
3480 TRACE("(%p) : returning %p\n", This, *ppShader);
3481 return WINED3D_OK;
3484 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3485 IWineD3DDevice *iface,
3486 UINT start,
3487 CONST BOOL *srcData,
3488 UINT count) {
3490 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3491 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3493 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3494 iface, srcData, start, count);
3496 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3498 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3499 for (i = 0; i < cnt; i++)
3500 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3502 for (i = start; i < cnt + start; ++i) {
3503 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3506 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3508 return WINED3D_OK;
3511 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3512 IWineD3DDevice *iface,
3513 UINT start,
3514 BOOL *dstData,
3515 UINT count) {
3517 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3518 int cnt = min(count, MAX_CONST_B - start);
3520 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3521 iface, dstData, start, count);
3523 if (dstData == NULL || cnt < 0)
3524 return WINED3DERR_INVALIDCALL;
3526 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3527 return WINED3D_OK;
3530 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3531 IWineD3DDevice *iface,
3532 UINT start,
3533 CONST int *srcData,
3534 UINT count) {
3536 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3537 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3539 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3540 iface, srcData, start, count);
3542 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3544 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3545 for (i = 0; i < cnt; i++)
3546 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3547 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3549 for (i = start; i < cnt + start; ++i) {
3550 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3553 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3555 return WINED3D_OK;
3558 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3559 IWineD3DDevice *iface,
3560 UINT start,
3561 int *dstData,
3562 UINT count) {
3564 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3565 int cnt = min(count, MAX_CONST_I - start);
3567 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3568 iface, dstData, start, count);
3570 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3571 return WINED3DERR_INVALIDCALL;
3573 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3574 return WINED3D_OK;
3577 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3578 IWineD3DDevice *iface,
3579 UINT start,
3580 CONST float *srcData,
3581 UINT count) {
3583 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3584 UINT i;
3586 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3587 iface, srcData, start, count);
3589 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3590 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3591 return WINED3DERR_INVALIDCALL;
3593 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3594 if(TRACE_ON(d3d)) {
3595 for (i = 0; i < count; i++)
3596 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3597 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3600 if (!This->isRecordingState)
3602 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3603 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3606 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3607 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3609 return WINED3D_OK;
3612 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3613 IWineD3DDevice *iface,
3614 UINT start,
3615 float *dstData,
3616 UINT count) {
3618 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3619 int cnt = min(count, This->d3d_vshader_constantF - start);
3621 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3622 iface, dstData, start, count);
3624 if (dstData == NULL || cnt < 0)
3625 return WINED3DERR_INVALIDCALL;
3627 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3628 return WINED3D_OK;
3631 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3632 DWORD i;
3633 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3635 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3639 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3641 DWORD i = This->rev_tex_unit_map[unit];
3642 DWORD j = This->texUnitMap[stage];
3644 This->texUnitMap[stage] = unit;
3645 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3647 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3650 This->rev_tex_unit_map[unit] = stage;
3651 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3653 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3657 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3658 int i;
3660 This->fixed_function_usage_map = 0;
3661 for (i = 0; i < MAX_TEXTURES; ++i) {
3662 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3663 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3664 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3665 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3666 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3667 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3668 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3669 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3671 if (color_op == WINED3DTOP_DISABLE) {
3672 /* Not used, and disable higher stages */
3673 break;
3676 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3677 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3678 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3679 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3680 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3681 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3682 This->fixed_function_usage_map |= (1 << i);
3685 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3686 This->fixed_function_usage_map |= (1 << (i + 1));
3691 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3692 unsigned int i, tex;
3693 WORD ffu_map;
3695 device_update_fixed_function_usage_map(This);
3696 ffu_map = This->fixed_function_usage_map;
3698 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3699 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3700 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3702 if (!(ffu_map & 1)) continue;
3704 if (This->texUnitMap[i] != i) {
3705 device_map_stage(This, i, i);
3706 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3707 markTextureStagesDirty(This, i);
3710 return;
3713 /* Now work out the mapping */
3714 tex = 0;
3715 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3717 if (!(ffu_map & 1)) continue;
3719 if (This->texUnitMap[i] != tex) {
3720 device_map_stage(This, i, tex);
3721 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3722 markTextureStagesDirty(This, i);
3725 ++tex;
3729 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3730 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3731 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3732 unsigned int i;
3734 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3735 if (sampler_type[i] && This->texUnitMap[i] != i)
3737 device_map_stage(This, i, i);
3738 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3739 if (i < MAX_TEXTURES) {
3740 markTextureStagesDirty(This, i);
3746 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3747 const DWORD *vshader_sampler_tokens, DWORD unit)
3749 DWORD current_mapping = This->rev_tex_unit_map[unit];
3751 /* Not currently used */
3752 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3754 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3755 /* Used by a fragment sampler */
3757 if (!pshader_sampler_tokens) {
3758 /* No pixel shader, check fixed function */
3759 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3762 /* Pixel shader, check the shader's sampler map */
3763 return !pshader_sampler_tokens[current_mapping];
3766 /* Used by a vertex sampler */
3767 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3770 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3771 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3772 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3773 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3774 int start = min(MAX_COMBINED_SAMPLERS, GL_LIMITS(combined_samplers)) - 1;
3775 int i;
3777 if (ps) {
3778 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3780 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3781 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3782 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3785 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3786 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3787 if (vshader_sampler_type[i])
3789 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3791 /* Already mapped somewhere */
3792 continue;
3795 while (start >= 0) {
3796 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3798 device_map_stage(This, vsampler_idx, start);
3799 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3801 --start;
3802 break;
3805 --start;
3811 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3812 BOOL vs = use_vs(This->stateBlock);
3813 BOOL ps = use_ps(This->stateBlock);
3815 * Rules are:
3816 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3817 * that would be really messy and require shader recompilation
3818 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3819 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3821 if (ps) {
3822 device_map_psamplers(This);
3823 } else {
3824 device_map_fixed_function_samplers(This);
3827 if (vs) {
3828 device_map_vsamplers(This, ps);
3832 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3833 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3834 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3835 This->updateStateBlock->pixelShader = pShader;
3836 This->updateStateBlock->changed.pixelShader = TRUE;
3838 /* Handle recording of state blocks */
3839 if (This->isRecordingState) {
3840 TRACE("Recording... not performing anything\n");
3843 if (This->isRecordingState) {
3844 TRACE("Recording... not performing anything\n");
3845 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3846 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3847 return WINED3D_OK;
3850 if(pShader == oldShader) {
3851 TRACE("App is setting the old pixel shader over, nothing to do\n");
3852 return WINED3D_OK;
3855 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3856 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3858 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3859 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3861 return WINED3D_OK;
3864 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3865 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3867 if (NULL == ppShader) {
3868 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3869 return WINED3DERR_INVALIDCALL;
3872 *ppShader = This->stateBlock->pixelShader;
3873 if (NULL != *ppShader) {
3874 IWineD3DPixelShader_AddRef(*ppShader);
3876 TRACE("(%p) : returning %p\n", This, *ppShader);
3877 return WINED3D_OK;
3880 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3881 IWineD3DDevice *iface,
3882 UINT start,
3883 CONST BOOL *srcData,
3884 UINT count) {
3886 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3887 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3889 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3890 iface, srcData, start, count);
3892 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3894 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3895 for (i = 0; i < cnt; i++)
3896 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3898 for (i = start; i < cnt + start; ++i) {
3899 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3902 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3904 return WINED3D_OK;
3907 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3908 IWineD3DDevice *iface,
3909 UINT start,
3910 BOOL *dstData,
3911 UINT count) {
3913 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3914 int cnt = min(count, MAX_CONST_B - start);
3916 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3917 iface, dstData, start, count);
3919 if (dstData == NULL || cnt < 0)
3920 return WINED3DERR_INVALIDCALL;
3922 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3923 return WINED3D_OK;
3926 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3927 IWineD3DDevice *iface,
3928 UINT start,
3929 CONST int *srcData,
3930 UINT count) {
3932 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3933 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3935 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3936 iface, srcData, start, count);
3938 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3940 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3941 for (i = 0; i < cnt; i++)
3942 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3943 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3945 for (i = start; i < cnt + start; ++i) {
3946 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3949 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3951 return WINED3D_OK;
3954 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3955 IWineD3DDevice *iface,
3956 UINT start,
3957 int *dstData,
3958 UINT count) {
3960 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3961 int cnt = min(count, MAX_CONST_I - start);
3963 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3964 iface, dstData, start, count);
3966 if (dstData == NULL || cnt < 0)
3967 return WINED3DERR_INVALIDCALL;
3969 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3970 return WINED3D_OK;
3973 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3974 IWineD3DDevice *iface,
3975 UINT start,
3976 CONST float *srcData,
3977 UINT count) {
3979 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3980 UINT i;
3982 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3983 iface, srcData, start, count);
3985 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3986 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3987 return WINED3DERR_INVALIDCALL;
3989 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3990 if(TRACE_ON(d3d)) {
3991 for (i = 0; i < count; i++)
3992 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3993 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3996 if (!This->isRecordingState)
3998 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3999 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4002 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
4003 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
4005 return WINED3D_OK;
4008 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4009 IWineD3DDevice *iface,
4010 UINT start,
4011 float *dstData,
4012 UINT count) {
4014 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4015 int cnt = min(count, This->d3d_pshader_constantF - start);
4017 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4018 iface, dstData, start, count);
4020 if (dstData == NULL || cnt < 0)
4021 return WINED3DERR_INVALIDCALL;
4023 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4024 return WINED3D_OK;
4027 /* Context activation is done by the caller. */
4028 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4029 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4030 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
4031 DWORD DestFVF)
4033 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4034 unsigned int i;
4035 WINED3DVIEWPORT vp;
4036 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4037 BOOL doClip;
4038 DWORD numTextures;
4040 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
4042 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4045 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
4047 ERR("Source has no position mask\n");
4048 return WINED3DERR_INVALIDCALL;
4051 /* We might access VBOs from this code, so hold the lock */
4052 ENTER_GL();
4054 if (dest->resource.allocatedMemory == NULL) {
4055 buffer_get_sysmem(dest);
4058 /* Get a pointer into the destination vbo(create one if none exists) and
4059 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4061 if (!dest->buffer_object && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT))
4063 dest->flags |= WINED3D_BUFFER_CREATEBO;
4064 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
4067 if (dest->buffer_object)
4069 unsigned char extrabytes = 0;
4070 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4071 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4072 * this may write 4 extra bytes beyond the area that should be written
4074 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4075 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4076 if(!dest_conv_addr) {
4077 ERR("Out of memory\n");
4078 /* Continue without storing converted vertices */
4080 dest_conv = dest_conv_addr;
4083 /* Should I clip?
4084 * a) WINED3DRS_CLIPPING is enabled
4085 * b) WINED3DVOP_CLIP is passed
4087 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4088 static BOOL warned = FALSE;
4090 * The clipping code is not quite correct. Some things need
4091 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4092 * so disable clipping for now.
4093 * (The graphics in Half-Life are broken, and my processvertices
4094 * test crashes with IDirect3DDevice3)
4095 doClip = TRUE;
4097 doClip = FALSE;
4098 if(!warned) {
4099 warned = TRUE;
4100 FIXME("Clipping is broken and disabled for now\n");
4102 } else doClip = FALSE;
4103 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4105 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4106 WINED3DTS_VIEW,
4107 &view_mat);
4108 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4109 WINED3DTS_PROJECTION,
4110 &proj_mat);
4111 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4112 WINED3DTS_WORLDMATRIX(0),
4113 &world_mat);
4115 TRACE("View mat:\n");
4116 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);
4117 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);
4118 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);
4119 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);
4121 TRACE("Proj mat:\n");
4122 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);
4123 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);
4124 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);
4125 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);
4127 TRACE("World mat:\n");
4128 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);
4129 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);
4130 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);
4131 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);
4133 /* Get the viewport */
4134 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4135 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4136 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4138 multiply_matrix(&mat,&view_mat,&world_mat);
4139 multiply_matrix(&mat,&proj_mat,&mat);
4141 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4143 for (i = 0; i < dwCount; i+= 1) {
4144 unsigned int tex_index;
4146 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4147 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4148 /* The position first */
4149 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
4150 const float *p = (const float *)(element->data + i * element->stride);
4151 float x, y, z, rhw;
4152 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4154 /* Multiplication with world, view and projection matrix */
4155 x = (p[0] * mat.u.s._11) + (p[1] * mat.u.s._21) + (p[2] * mat.u.s._31) + (1.0f * mat.u.s._41);
4156 y = (p[0] * mat.u.s._12) + (p[1] * mat.u.s._22) + (p[2] * mat.u.s._32) + (1.0f * mat.u.s._42);
4157 z = (p[0] * mat.u.s._13) + (p[1] * mat.u.s._23) + (p[2] * mat.u.s._33) + (1.0f * mat.u.s._43);
4158 rhw = (p[0] * mat.u.s._14) + (p[1] * mat.u.s._24) + (p[2] * mat.u.s._34) + (1.0f * mat.u.s._44);
4160 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4162 /* WARNING: The following things are taken from d3d7 and were not yet checked
4163 * against d3d8 or d3d9!
4166 /* Clipping conditions: From msdn
4168 * A vertex is clipped if it does not match the following requirements
4169 * -rhw < x <= rhw
4170 * -rhw < y <= rhw
4171 * 0 < z <= rhw
4172 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4174 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4175 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4179 if( !doClip ||
4180 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4181 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4182 ( rhw > eps ) ) ) {
4184 /* "Normal" viewport transformation (not clipped)
4185 * 1) The values are divided by rhw
4186 * 2) The y axis is negative, so multiply it with -1
4187 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4188 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4189 * 4) Multiply x with Width/2 and add Width/2
4190 * 5) The same for the height
4191 * 6) Add the viewpoint X and Y to the 2D coordinates and
4192 * The minimum Z value to z
4193 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4195 * Well, basically it's simply a linear transformation into viewport
4196 * coordinates
4199 x /= rhw;
4200 y /= rhw;
4201 z /= rhw;
4203 y *= -1;
4205 x *= vp.Width / 2;
4206 y *= vp.Height / 2;
4207 z *= vp.MaxZ - vp.MinZ;
4209 x += vp.Width / 2 + vp.X;
4210 y += vp.Height / 2 + vp.Y;
4211 z += vp.MinZ;
4213 rhw = 1 / rhw;
4214 } else {
4215 /* That vertex got clipped
4216 * Contrary to OpenGL it is not dropped completely, it just
4217 * undergoes a different calculation.
4219 TRACE("Vertex got clipped\n");
4220 x += rhw;
4221 y += rhw;
4223 x /= 2;
4224 y /= 2;
4226 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4227 * outside of the main vertex buffer memory. That needs some more
4228 * investigation...
4232 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4235 ( (float *) dest_ptr)[0] = x;
4236 ( (float *) dest_ptr)[1] = y;
4237 ( (float *) dest_ptr)[2] = z;
4238 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4240 dest_ptr += 3 * sizeof(float);
4242 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4243 dest_ptr += sizeof(float);
4246 if(dest_conv) {
4247 float w = 1 / rhw;
4248 ( (float *) dest_conv)[0] = x * w;
4249 ( (float *) dest_conv)[1] = y * w;
4250 ( (float *) dest_conv)[2] = z * w;
4251 ( (float *) dest_conv)[3] = w;
4253 dest_conv += 3 * sizeof(float);
4255 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4256 dest_conv += sizeof(float);
4260 if (DestFVF & WINED3DFVF_PSIZE) {
4261 dest_ptr += sizeof(DWORD);
4262 if(dest_conv) dest_conv += sizeof(DWORD);
4264 if (DestFVF & WINED3DFVF_NORMAL) {
4265 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4266 const float *normal = (const float *)(element->data + i * element->stride);
4267 /* AFAIK this should go into the lighting information */
4268 FIXME("Didn't expect the destination to have a normal\n");
4269 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4270 if(dest_conv) {
4271 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4275 if (DestFVF & WINED3DFVF_DIFFUSE) {
4276 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4277 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4278 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4280 static BOOL warned = FALSE;
4282 if(!warned) {
4283 ERR("No diffuse color in source, but destination has one\n");
4284 warned = TRUE;
4287 *( (DWORD *) dest_ptr) = 0xffffffff;
4288 dest_ptr += sizeof(DWORD);
4290 if(dest_conv) {
4291 *( (DWORD *) dest_conv) = 0xffffffff;
4292 dest_conv += sizeof(DWORD);
4295 else {
4296 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4297 if(dest_conv) {
4298 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4299 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4300 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4301 dest_conv += sizeof(DWORD);
4306 if (DestFVF & WINED3DFVF_SPECULAR)
4308 /* What's the color value in the feedback buffer? */
4309 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4310 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4311 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4313 static BOOL warned = FALSE;
4315 if(!warned) {
4316 ERR("No specular color in source, but destination has one\n");
4317 warned = TRUE;
4320 *( (DWORD *) dest_ptr) = 0xFF000000;
4321 dest_ptr += sizeof(DWORD);
4323 if(dest_conv) {
4324 *( (DWORD *) dest_conv) = 0xFF000000;
4325 dest_conv += sizeof(DWORD);
4328 else {
4329 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4330 if(dest_conv) {
4331 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4332 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4333 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4334 dest_conv += sizeof(DWORD);
4339 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4340 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4341 const float *tex_coord = (const float *)(element->data + i * element->stride);
4342 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4344 ERR("No source texture, but destination requests one\n");
4345 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4346 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4348 else {
4349 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4350 if(dest_conv) {
4351 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4357 if(dest_conv) {
4358 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4359 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4360 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4361 dwCount * get_flexible_vertex_size(DestFVF),
4362 dest_conv_addr));
4363 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4364 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4367 LEAVE_GL();
4369 return WINED3D_OK;
4371 #undef copy_and_next
4373 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4374 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4375 DWORD DestFVF)
4377 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4378 struct wined3d_stream_info stream_info;
4379 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4380 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4382 if(pVertexDecl) {
4383 ERR("Output vertex declaration not implemented yet\n");
4386 /* Need any context to write to the vbo. */
4387 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
4389 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4390 * control the streamIsUP flag, thus restore it afterwards.
4392 This->stateBlock->streamIsUP = FALSE;
4393 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4394 This->stateBlock->streamIsUP = streamWasUP;
4396 if(vbo || SrcStartIndex) {
4397 unsigned int i;
4398 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4399 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4401 * Also get the start index in, but only loop over all elements if there's something to add at all.
4403 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4405 struct wined3d_stream_info_element *e;
4407 if (!(stream_info.use_map & (1 << i))) continue;
4409 e = &stream_info.elements[i];
4410 if (e->buffer_object)
4412 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
4413 e->buffer_object = 0;
4414 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
4415 ENTER_GL();
4416 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4417 vb->buffer_object = 0;
4418 LEAVE_GL();
4420 if (e->data) e->data += e->stride * SrcStartIndex;
4424 return process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4425 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4428 /*****
4429 * Get / Set Texture Stage States
4430 * TODO: Verify against dx9 definitions
4431 *****/
4432 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4433 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4434 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4436 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4438 if (Stage >= MAX_TEXTURES) {
4439 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4440 return WINED3D_OK;
4443 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4444 This->updateStateBlock->textureState[Stage][Type] = Value;
4446 if (This->isRecordingState) {
4447 TRACE("Recording... not performing anything\n");
4448 return WINED3D_OK;
4451 /* Checked after the assignments to allow proper stateblock recording */
4452 if(oldValue == Value) {
4453 TRACE("App is setting the old value over, nothing to do\n");
4454 return WINED3D_OK;
4457 if(Stage > This->stateBlock->lowest_disabled_stage &&
4458 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4459 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4460 * Changes in other states are important on disabled stages too
4462 return WINED3D_OK;
4465 if(Type == WINED3DTSS_COLOROP) {
4466 unsigned int i;
4468 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4469 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4470 * they have to be disabled
4472 * The current stage is dirtified below.
4474 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4475 TRACE("Additionally dirtifying stage %u\n", i);
4476 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4478 This->stateBlock->lowest_disabled_stage = Stage;
4479 TRACE("New lowest disabled: %u\n", Stage);
4480 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4481 /* Previously disabled stage enabled. Stages above it may need enabling
4482 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4483 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4485 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4488 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4489 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4490 break;
4492 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4493 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4495 This->stateBlock->lowest_disabled_stage = i;
4496 TRACE("New lowest disabled: %u\n", i);
4500 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4502 return WINED3D_OK;
4505 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4506 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4507 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4508 *pValue = This->updateStateBlock->textureState[Stage][Type];
4509 return WINED3D_OK;
4512 /*****
4513 * Get / Set Texture
4514 *****/
4515 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4517 IWineD3DBaseTexture *oldTexture;
4519 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4521 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4522 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4525 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4526 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4527 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4530 oldTexture = This->updateStateBlock->textures[Stage];
4532 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4533 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
4535 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4536 return WINED3DERR_INVALIDCALL;
4539 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4540 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4542 This->updateStateBlock->changed.textures |= 1 << Stage;
4543 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4544 This->updateStateBlock->textures[Stage] = pTexture;
4546 /* Handle recording of state blocks */
4547 if (This->isRecordingState) {
4548 TRACE("Recording... not performing anything\n");
4549 return WINED3D_OK;
4552 if(oldTexture == pTexture) {
4553 TRACE("App is setting the same texture again, nothing to do\n");
4554 return WINED3D_OK;
4557 /** NOTE: MSDN says that setTexture increases the reference count,
4558 * and that the application must set the texture back to null (or have a leaky application),
4559 * This means we should pass the refcount up to the parent
4560 *******************************/
4561 if (NULL != This->updateStateBlock->textures[Stage]) {
4562 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4563 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4564 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4566 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4568 if (!oldTexture || dimensions != IWineD3DBaseTexture_GetTextureDimensions(oldTexture))
4570 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4573 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4574 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4575 * so the COLOROP and ALPHAOP have to be dirtified.
4577 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4578 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4580 if(bindCount == 1) {
4581 new->baseTexture.sampler = Stage;
4583 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4587 if (NULL != oldTexture) {
4588 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4589 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4591 IWineD3DBaseTexture_Release(oldTexture);
4592 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4593 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4594 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4597 if(bindCount && old->baseTexture.sampler == Stage) {
4598 int i;
4599 /* Have to do a search for the other sampler(s) where the texture is bound to
4600 * Shouldn't happen as long as apps bind a texture only to one stage
4602 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4603 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4604 if(This->updateStateBlock->textures[i] == oldTexture) {
4605 old->baseTexture.sampler = i;
4606 break;
4612 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4614 return WINED3D_OK;
4617 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4618 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4620 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4622 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4623 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4626 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4627 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4628 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4631 *ppTexture=This->stateBlock->textures[Stage];
4632 if (*ppTexture)
4633 IWineD3DBaseTexture_AddRef(*ppTexture);
4635 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4637 return WINED3D_OK;
4640 /*****
4641 * Get Back Buffer
4642 *****/
4643 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4644 IWineD3DSurface **ppBackBuffer) {
4645 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4646 IWineD3DSwapChain *swapChain;
4647 HRESULT hr;
4649 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4651 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4652 if (hr == WINED3D_OK) {
4653 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4654 IWineD3DSwapChain_Release(swapChain);
4655 } else {
4656 *ppBackBuffer = NULL;
4658 return hr;
4661 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4662 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4663 WARN("(%p) : stub, calling idirect3d for now\n", This);
4664 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4667 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4668 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4669 IWineD3DSwapChain *swapChain;
4670 HRESULT hr;
4672 if(iSwapChain > 0) {
4673 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4674 if (hr == WINED3D_OK) {
4675 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4676 IWineD3DSwapChain_Release(swapChain);
4677 } else {
4678 FIXME("(%p) Error getting display mode\n", This);
4680 } else {
4681 /* Don't read the real display mode,
4682 but return the stored mode instead. X11 can't change the color
4683 depth, and some apps are pretty angry if they SetDisplayMode from
4684 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4686 Also don't relay to the swapchain because with ddraw it's possible
4687 that there isn't a swapchain at all */
4688 pMode->Width = This->ddraw_width;
4689 pMode->Height = This->ddraw_height;
4690 pMode->Format = This->ddraw_format;
4691 pMode->RefreshRate = 0;
4692 hr = WINED3D_OK;
4695 return hr;
4698 /*****
4699 * Stateblock related functions
4700 *****/
4702 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4703 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4704 IWineD3DStateBlock *stateblock;
4705 HRESULT hr;
4707 TRACE("(%p)\n", This);
4709 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4711 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4712 if (FAILED(hr)) return hr;
4714 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4715 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4716 This->isRecordingState = TRUE;
4718 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4720 return WINED3D_OK;
4723 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4724 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4725 unsigned int i, j;
4726 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4728 if (!This->isRecordingState) {
4729 WARN("(%p) not recording! returning error\n", This);
4730 *ppStateBlock = NULL;
4731 return WINED3DERR_INVALIDCALL;
4734 for (i = 0; i <= WINEHIGHEST_RENDER_STATE >> 5; ++i)
4736 DWORD map = object->changed.renderState[i];
4737 for (j = 0; map; map >>= 1, ++j)
4739 if (!(map & 1)) continue;
4741 object->contained_render_states[object->num_contained_render_states++] = (i << 5) | j;
4745 for (i = 0; i <= HIGHEST_TRANSFORMSTATE >> 5; ++i)
4747 DWORD map = object->changed.transform[i];
4748 for (j = 0; map; map >>= 1, ++j)
4750 if (!(map & 1)) continue;
4752 object->contained_transform_states[object->num_contained_transform_states++] = (i << 5) | j;
4755 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4756 if(object->changed.vertexShaderConstantsF[i]) {
4757 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4758 object->num_contained_vs_consts_f++;
4761 for(i = 0; i < MAX_CONST_I; i++) {
4762 if (object->changed.vertexShaderConstantsI & (1 << i))
4764 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4765 object->num_contained_vs_consts_i++;
4768 for(i = 0; i < MAX_CONST_B; i++) {
4769 if (object->changed.vertexShaderConstantsB & (1 << i))
4771 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4772 object->num_contained_vs_consts_b++;
4775 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
4777 if (object->changed.pixelShaderConstantsF[i])
4779 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
4780 ++object->num_contained_ps_consts_f;
4783 for(i = 0; i < MAX_CONST_I; i++) {
4784 if (object->changed.pixelShaderConstantsI & (1 << i))
4786 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4787 object->num_contained_ps_consts_i++;
4790 for(i = 0; i < MAX_CONST_B; i++) {
4791 if (object->changed.pixelShaderConstantsB & (1 << i))
4793 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4794 object->num_contained_ps_consts_b++;
4797 for(i = 0; i < MAX_TEXTURES; i++) {
4798 DWORD map = object->changed.textureState[i];
4800 for(j = 0; map; map >>= 1, ++j)
4802 if (!(map & 1)) continue;
4804 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4805 object->contained_tss_states[object->num_contained_tss_states].state = j;
4806 ++object->num_contained_tss_states;
4809 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4810 DWORD map = object->changed.samplerState[i];
4812 for (j = 0; map; map >>= 1, ++j)
4814 if (!(map & 1)) continue;
4816 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4817 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4818 ++object->num_contained_sampler_states;
4822 *ppStateBlock = (IWineD3DStateBlock*) object;
4823 This->isRecordingState = FALSE;
4824 This->updateStateBlock = This->stateBlock;
4825 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4826 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4827 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4828 return WINED3D_OK;
4831 /*****
4832 * Scene related functions
4833 *****/
4834 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4835 /* At the moment we have no need for any functionality at the beginning
4836 of a scene */
4837 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4838 TRACE("(%p)\n", This);
4840 if(This->inScene) {
4841 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4842 return WINED3DERR_INVALIDCALL;
4844 This->inScene = TRUE;
4845 return WINED3D_OK;
4848 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4849 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4850 TRACE("(%p)\n", This);
4852 if(!This->inScene) {
4853 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4854 return WINED3DERR_INVALIDCALL;
4857 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
4858 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4859 wglFlush();
4860 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4861 * fails
4864 This->inScene = FALSE;
4865 return WINED3D_OK;
4868 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4869 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4870 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4871 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4872 IWineD3DSwapChain *swapChain = NULL;
4873 int i;
4874 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4876 TRACE("(%p) Presenting the frame\n", This);
4878 for(i = 0 ; i < swapchains ; i ++) {
4880 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4881 TRACE("presentinng chain %d, %p\n", i, swapChain);
4882 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4883 IWineD3DSwapChain_Release(swapChain);
4886 return WINED3D_OK;
4889 /* Not called from the VTable (internal subroutine) */
4890 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4891 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4892 float Z, DWORD Stencil) {
4893 GLbitfield glMask = 0;
4894 unsigned int i;
4895 WINED3DRECT curRect;
4896 RECT vp_rect;
4897 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4898 UINT drawable_width, drawable_height;
4899 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4900 IWineD3DSwapChainImpl *swapchain = NULL;
4901 struct wined3d_context *context;
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 context = ActivateContext(This, (IWineD3DSurface *)target, CTXUSAGE_CLEAR);
4939 target->get_drawable_size(context, &drawable_width, &drawable_height);
4941 ENTER_GL();
4943 /* Only set the values up once, as they are not changing */
4944 if (Flags & WINED3DCLEAR_STENCIL) {
4945 glClearStencil(Stencil);
4946 checkGLcall("glClearStencil");
4947 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4948 glStencilMask(0xFFFFFFFF);
4951 if (Flags & WINED3DCLEAR_ZBUFFER) {
4952 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4953 glDepthMask(GL_TRUE);
4954 glClearDepth(Z);
4955 checkGLcall("glClearDepth");
4956 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4957 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4959 if (vp->X != 0 || vp->Y != 0 ||
4960 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4961 surface_load_ds_location(This->stencilBufferTarget, context, location);
4963 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4964 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4965 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4966 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4967 surface_load_ds_location(This->stencilBufferTarget, context, location);
4969 else if (Count > 0 && pRects && (
4970 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4971 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4972 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4973 surface_load_ds_location(This->stencilBufferTarget, context, location);
4977 if (Flags & WINED3DCLEAR_TARGET) {
4978 TRACE("Clearing screen with glClear to color %x\n", Color);
4979 glClearColor(D3DCOLOR_R(Color),
4980 D3DCOLOR_G(Color),
4981 D3DCOLOR_B(Color),
4982 D3DCOLOR_A(Color));
4983 checkGLcall("glClearColor");
4985 /* Clear ALL colors! */
4986 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4987 glMask = glMask | GL_COLOR_BUFFER_BIT;
4990 vp_rect.left = vp->X;
4991 vp_rect.top = vp->Y;
4992 vp_rect.right = vp->X + vp->Width;
4993 vp_rect.bottom = vp->Y + vp->Height;
4994 if (!(Count > 0 && pRects)) {
4995 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4996 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4998 if (context->render_offscreen)
5000 glScissor(vp_rect.left, vp_rect.top,
5001 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5002 } else {
5003 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5004 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5006 checkGLcall("glScissor");
5007 glClear(glMask);
5008 checkGLcall("glClear");
5009 } else {
5010 /* Now process each rect in turn */
5011 for (i = 0; i < Count; i++) {
5012 /* Note gl uses lower left, width/height */
5013 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5014 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5015 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5017 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5018 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5019 curRect.x1, (target->currentDesc.Height - curRect.y2),
5020 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5022 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5023 * The rectangle is not cleared, no error is returned, but further rectanlges are
5024 * still cleared if they are valid
5026 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5027 TRACE("Rectangle with negative dimensions, ignoring\n");
5028 continue;
5031 if (context->render_offscreen)
5033 glScissor(curRect.x1, curRect.y1,
5034 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5035 } else {
5036 glScissor(curRect.x1, drawable_height - curRect.y2,
5037 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5039 checkGLcall("glScissor");
5041 glClear(glMask);
5042 checkGLcall("glClear");
5046 /* Restore the old values (why..?) */
5047 if (Flags & WINED3DCLEAR_STENCIL) {
5048 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5050 if (Flags & WINED3DCLEAR_TARGET) {
5051 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5052 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5053 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5054 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5055 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5057 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5058 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5060 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
5062 if (Flags & WINED3DCLEAR_ZBUFFER) {
5063 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5064 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5065 surface_modify_ds_location(This->stencilBufferTarget, location);
5068 LEAVE_GL();
5070 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5071 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5072 wglFlush();
5074 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5077 return WINED3D_OK;
5080 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5081 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5082 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5083 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5085 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5086 Count, pRects, Flags, Color, Z, Stencil);
5088 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5089 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5090 /* TODO: What about depth stencil buffers without stencil bits? */
5091 return WINED3DERR_INVALIDCALL;
5094 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5097 /*****
5098 * Drawing functions
5099 *****/
5101 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
5102 WINED3DPRIMITIVETYPE primitive_type)
5104 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5106 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
5108 This->updateStateBlock->changed.primitive_type = TRUE;
5109 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
5112 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
5113 WINED3DPRIMITIVETYPE *primitive_type)
5115 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5117 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
5119 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
5121 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
5124 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
5126 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5128 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
5130 if(!This->stateBlock->vertexDecl) {
5131 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5132 return WINED3DERR_INVALIDCALL;
5135 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5136 if(This->stateBlock->streamIsUP) {
5137 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5138 This->stateBlock->streamIsUP = FALSE;
5141 if(This->stateBlock->loadBaseVertexIndex != 0) {
5142 This->stateBlock->loadBaseVertexIndex = 0;
5143 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5145 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5146 drawPrimitive(iface, vertex_count, 0/* NumVertices */, StartVertex /* start_idx */,
5147 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5148 return WINED3D_OK;
5151 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5152 UINT minIndex, UINT NumVertices, UINT startIndex, UINT index_count)
5154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5155 UINT idxStride = 2;
5156 IWineD3DBuffer *pIB;
5157 GLuint vbo;
5159 pIB = This->stateBlock->pIndexData;
5160 if (!pIB) {
5161 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5162 * without an index buffer set. (The first time at least...)
5163 * D3D8 simply dies, but I doubt it can do much harm to return
5164 * D3DERR_INVALIDCALL there as well. */
5165 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5166 return WINED3DERR_INVALIDCALL;
5169 if(!This->stateBlock->vertexDecl) {
5170 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5171 return WINED3DERR_INVALIDCALL;
5174 if(This->stateBlock->streamIsUP) {
5175 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5176 This->stateBlock->streamIsUP = FALSE;
5178 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
5180 TRACE("(%p) : min %u, vertex count %u, startIdx %u, index count %u\n",
5181 This, minIndex, NumVertices, startIndex, index_count);
5183 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
5184 idxStride = 2;
5185 } else {
5186 idxStride = 4;
5189 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5190 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5191 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5194 drawPrimitive(iface, index_count, NumVertices, startIndex, idxStride,
5195 vbo ? NULL : ((struct wined3d_buffer *) pIB)->resource.allocatedMemory, minIndex);
5197 return WINED3D_OK;
5200 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
5201 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5203 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5204 IWineD3DBuffer *vb;
5206 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
5207 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
5209 if(!This->stateBlock->vertexDecl) {
5210 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5211 return WINED3DERR_INVALIDCALL;
5214 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5215 vb = This->stateBlock->streamSource[0];
5216 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5217 if (vb) IWineD3DBuffer_Release(vb);
5218 This->stateBlock->streamOffset[0] = 0;
5219 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5220 This->stateBlock->streamIsUP = TRUE;
5221 This->stateBlock->loadBaseVertexIndex = 0;
5223 /* TODO: Only mark dirty if drawing from a different UP address */
5224 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5226 drawPrimitive(iface, vertex_count, 0 /* NumVertices */, 0 /* start_idx */,
5227 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5229 /* MSDN specifies stream zero settings must be set to NULL */
5230 This->stateBlock->streamStride[0] = 0;
5231 This->stateBlock->streamSource[0] = NULL;
5233 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5234 * the new stream sources or use UP drawing again
5236 return WINED3D_OK;
5239 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, UINT MinVertexIndex,
5240 UINT NumVertices, UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
5241 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5243 int idxStride;
5244 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5245 IWineD3DBuffer *vb;
5246 IWineD3DBuffer *ib;
5248 TRACE("(%p) : MinVtxIdx %u, NumVIdx %u, index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u\n",
5249 This, MinVertexIndex, NumVertices, index_count, pIndexData,
5250 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5252 if(!This->stateBlock->vertexDecl) {
5253 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5254 return WINED3DERR_INVALIDCALL;
5257 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
5258 idxStride = 2;
5259 } else {
5260 idxStride = 4;
5263 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5264 vb = This->stateBlock->streamSource[0];
5265 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5266 if (vb) IWineD3DBuffer_Release(vb);
5267 This->stateBlock->streamIsUP = TRUE;
5268 This->stateBlock->streamOffset[0] = 0;
5269 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5271 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5272 This->stateBlock->baseVertexIndex = 0;
5273 This->stateBlock->loadBaseVertexIndex = 0;
5274 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5275 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5276 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5278 drawPrimitive(iface, index_count, NumVertices, 0 /* start_idx */,
5279 idxStride, pIndexData, MinVertexIndex);
5281 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5282 This->stateBlock->streamSource[0] = NULL;
5283 This->stateBlock->streamStride[0] = 0;
5284 ib = This->stateBlock->pIndexData;
5285 if(ib) {
5286 IWineD3DBuffer_Release(ib);
5287 This->stateBlock->pIndexData = NULL;
5289 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5290 * SetStreamSource to specify a vertex buffer
5293 return WINED3D_OK;
5296 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5297 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
5299 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5301 /* Mark the state dirty until we have nicer tracking
5302 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5303 * that value.
5305 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5306 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5307 This->stateBlock->baseVertexIndex = 0;
5308 This->up_strided = DrawPrimStrideData;
5309 drawPrimitive(iface, vertex_count, 0, 0, 0, NULL, 0);
5310 This->up_strided = NULL;
5311 return WINED3D_OK;
5314 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5315 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
5316 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
5318 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5319 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5321 /* Mark the state dirty until we have nicer tracking
5322 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5323 * that value.
5325 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5326 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5327 This->stateBlock->streamIsUP = TRUE;
5328 This->stateBlock->baseVertexIndex = 0;
5329 This->up_strided = DrawPrimStrideData;
5330 drawPrimitive(iface, vertex_count, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData, 0 /* minindex */);
5331 This->up_strided = NULL;
5332 return WINED3D_OK;
5335 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5336 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5337 * not callable by the app directly no parameter validation checks are needed here.
5339 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5340 WINED3DLOCKED_BOX src;
5341 WINED3DLOCKED_BOX dst;
5342 HRESULT hr;
5343 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5345 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5346 * dirtification to improve loading performance.
5348 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5349 if(FAILED(hr)) return hr;
5350 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5351 if(FAILED(hr)) {
5352 IWineD3DVolume_UnlockBox(pSourceVolume);
5353 return hr;
5356 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5358 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5359 if(FAILED(hr)) {
5360 IWineD3DVolume_UnlockBox(pSourceVolume);
5361 } else {
5362 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5364 return hr;
5367 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5368 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5369 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5370 HRESULT hr = WINED3D_OK;
5371 WINED3DRESOURCETYPE sourceType;
5372 WINED3DRESOURCETYPE destinationType;
5373 int i ,levels;
5375 /* TODO: think about moving the code into IWineD3DBaseTexture */
5377 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5379 /* verify that the source and destination textures aren't NULL */
5380 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5381 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5382 This, pSourceTexture, pDestinationTexture);
5383 hr = WINED3DERR_INVALIDCALL;
5386 if (pSourceTexture == pDestinationTexture) {
5387 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5388 This, pSourceTexture, pDestinationTexture);
5389 hr = WINED3DERR_INVALIDCALL;
5391 /* Verify that the source and destination textures are the same type */
5392 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5393 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5395 if (sourceType != destinationType) {
5396 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5397 This);
5398 hr = WINED3DERR_INVALIDCALL;
5401 /* check that both textures have the identical numbers of levels */
5402 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5403 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5404 hr = WINED3DERR_INVALIDCALL;
5407 if (WINED3D_OK == hr) {
5408 IWineD3DBaseTextureImpl *pDestImpl = (IWineD3DBaseTextureImpl *) pDestinationTexture;
5410 /* Make sure that the destination texture is loaded */
5411 pDestImpl->baseTexture.internal_preload(pDestinationTexture, SRGB_RGB);
5413 /* Update every surface level of the texture */
5414 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5416 switch (sourceType) {
5417 case WINED3DRTYPE_TEXTURE:
5419 IWineD3DSurface *srcSurface;
5420 IWineD3DSurface *destSurface;
5422 for (i = 0 ; i < levels ; ++i) {
5423 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5424 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5425 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5426 IWineD3DSurface_Release(srcSurface);
5427 IWineD3DSurface_Release(destSurface);
5428 if (WINED3D_OK != hr) {
5429 WARN("(%p) : Call to update surface failed\n", This);
5430 return hr;
5434 break;
5435 case WINED3DRTYPE_CUBETEXTURE:
5437 IWineD3DSurface *srcSurface;
5438 IWineD3DSurface *destSurface;
5439 WINED3DCUBEMAP_FACES faceType;
5441 for (i = 0 ; i < levels ; ++i) {
5442 /* Update each cube face */
5443 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5444 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5445 if (WINED3D_OK != hr) {
5446 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5447 } else {
5448 TRACE("Got srcSurface %p\n", srcSurface);
5450 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5451 if (WINED3D_OK != hr) {
5452 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5453 } else {
5454 TRACE("Got desrSurface %p\n", destSurface);
5456 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5457 IWineD3DSurface_Release(srcSurface);
5458 IWineD3DSurface_Release(destSurface);
5459 if (WINED3D_OK != hr) {
5460 WARN("(%p) : Call to update surface failed\n", This);
5461 return hr;
5466 break;
5468 case WINED3DRTYPE_VOLUMETEXTURE:
5470 IWineD3DVolume *srcVolume = NULL;
5471 IWineD3DVolume *destVolume = NULL;
5473 for (i = 0 ; i < levels ; ++i) {
5474 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5475 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5476 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5477 IWineD3DVolume_Release(srcVolume);
5478 IWineD3DVolume_Release(destVolume);
5479 if (WINED3D_OK != hr) {
5480 WARN("(%p) : Call to update volume failed\n", This);
5481 return hr;
5485 break;
5487 default:
5488 FIXME("(%p) : Unsupported source and destination type\n", This);
5489 hr = WINED3DERR_INVALIDCALL;
5493 return hr;
5496 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5497 IWineD3DSwapChain *swapChain;
5498 HRESULT hr;
5499 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5500 if(hr == WINED3D_OK) {
5501 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5502 IWineD3DSwapChain_Release(swapChain);
5504 return hr;
5507 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5508 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5509 IWineD3DBaseTextureImpl *texture;
5510 DWORD i;
5512 TRACE("(%p) : %p\n", This, pNumPasses);
5514 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5515 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5516 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5517 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5519 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5520 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5521 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5524 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5525 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5527 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5528 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5529 return E_FAIL;
5531 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5532 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5533 return E_FAIL;
5535 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5536 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5537 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5538 return E_FAIL;
5542 /* return a sensible default */
5543 *pNumPasses = 1;
5545 TRACE("returning D3D_OK\n");
5546 return WINED3D_OK;
5549 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5551 int i;
5553 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5554 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5555 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8
5556 || texture->resource.format_desc->format == WINED3DFMT_A8P8))
5558 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5563 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5564 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5565 int j;
5566 UINT NewSize;
5567 PALETTEENTRY **palettes;
5569 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5571 if (PaletteNumber >= MAX_PALETTES) {
5572 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5573 return WINED3DERR_INVALIDCALL;
5576 if (PaletteNumber >= This->NumberOfPalettes) {
5577 NewSize = This->NumberOfPalettes;
5578 do {
5579 NewSize *= 2;
5580 } while(PaletteNumber >= NewSize);
5581 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5582 if (!palettes) {
5583 ERR("Out of memory!\n");
5584 return E_OUTOFMEMORY;
5586 This->palettes = palettes;
5587 This->NumberOfPalettes = NewSize;
5590 if (!This->palettes[PaletteNumber]) {
5591 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5592 if (!This->palettes[PaletteNumber]) {
5593 ERR("Out of memory!\n");
5594 return E_OUTOFMEMORY;
5598 for (j = 0; j < 256; ++j) {
5599 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5600 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5601 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5602 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5604 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5605 TRACE("(%p) : returning\n", This);
5606 return WINED3D_OK;
5609 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5610 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5611 int j;
5612 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5613 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5614 /* What happens in such situation isn't documented; Native seems to silently abort
5615 on such conditions. Return Invalid Call. */
5616 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5617 return WINED3DERR_INVALIDCALL;
5619 for (j = 0; j < 256; ++j) {
5620 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5621 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5622 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5623 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5625 TRACE("(%p) : returning\n", This);
5626 return WINED3D_OK;
5629 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5630 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5631 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5632 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5633 (tested with reference rasterizer). Return Invalid Call. */
5634 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5635 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5636 return WINED3DERR_INVALIDCALL;
5638 /*TODO: stateblocks */
5639 if (This->currentPalette != PaletteNumber) {
5640 This->currentPalette = PaletteNumber;
5641 dirtify_p8_texture_samplers(This);
5643 TRACE("(%p) : returning\n", This);
5644 return WINED3D_OK;
5647 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5648 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5649 if (PaletteNumber == NULL) {
5650 WARN("(%p) : returning Invalid Call\n", This);
5651 return WINED3DERR_INVALIDCALL;
5653 /*TODO: stateblocks */
5654 *PaletteNumber = This->currentPalette;
5655 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5656 return WINED3D_OK;
5659 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5660 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5661 static BOOL warned;
5662 if (!warned)
5664 FIXME("(%p) : stub\n", This);
5665 warned = TRUE;
5668 This->softwareVertexProcessing = bSoftware;
5669 return WINED3D_OK;
5673 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5675 static BOOL warned;
5676 if (!warned)
5678 FIXME("(%p) : stub\n", This);
5679 warned = TRUE;
5681 return This->softwareVertexProcessing;
5685 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5686 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5687 IWineD3DSwapChain *swapChain;
5688 HRESULT hr;
5690 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5692 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5693 if(hr == WINED3D_OK){
5694 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5695 IWineD3DSwapChain_Release(swapChain);
5696 }else{
5697 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5699 return hr;
5703 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5704 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5705 static BOOL warned;
5706 if(nSegments != 0.0f) {
5707 if (!warned)
5709 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5710 warned = TRUE;
5713 return WINED3D_OK;
5716 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5717 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5718 static BOOL warned;
5719 if (!warned)
5721 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5722 warned = TRUE;
5724 return 0.0f;
5727 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5728 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5729 /** TODO: remove casts to IWineD3DSurfaceImpl
5730 * NOTE: move code to surface to accomplish this
5731 ****************************************/
5732 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5733 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)pDestinationSurface;
5734 int srcWidth, srcHeight;
5735 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5736 WINED3DFORMAT destFormat, srcFormat;
5737 UINT destSize;
5738 int srcLeft, destLeft, destTop;
5739 WINED3DPOOL srcPool, destPool;
5740 int offset = 0;
5741 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5742 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
5743 GLenum dummy;
5744 DWORD sampler;
5745 int bpp;
5746 CONVERT_TYPES convert = NO_CONVERSION;
5748 WINED3DSURFACE_DESC winedesc;
5750 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5752 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5753 srcSurfaceWidth = winedesc.width;
5754 srcSurfaceHeight = winedesc.height;
5755 srcPool = winedesc.pool;
5756 srcFormat = winedesc.format;
5758 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5759 destSurfaceWidth = winedesc.width;
5760 destSurfaceHeight = winedesc.height;
5761 destPool = winedesc.pool;
5762 destFormat = winedesc.format;
5763 destSize = winedesc.size;
5765 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5766 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5767 return WINED3DERR_INVALIDCALL;
5770 /* This call loads the opengl surface directly, instead of copying the surface to the
5771 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5772 * copy in sysmem and use regular surface loading.
5774 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5775 if(convert != NO_CONVERSION) {
5776 return IWineD3DSurface_BltFast(pDestinationSurface,
5777 pDestPoint ? pDestPoint->x : 0,
5778 pDestPoint ? pDestPoint->y : 0,
5779 pSourceSurface, pSourceRect, 0);
5782 if (destFormat == WINED3DFMT_UNKNOWN) {
5783 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5784 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5786 /* Get the update surface description */
5787 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5790 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
5792 ENTER_GL();
5793 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5794 checkGLcall("glActiveTextureARB");
5795 LEAVE_GL();
5797 /* Make sure the surface is loaded and up to date */
5798 surface_internal_preload(pDestinationSurface, SRGB_RGB);
5799 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5801 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
5802 dst_format_desc = dst_impl->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, dst_impl->texture_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(dst_impl->texture_target, dst_impl->texture_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(dst_impl->texture_target, dst_impl->texture_level,
5869 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
5872 else
5874 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_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 != WINED3D_UNMAPPED_STAGE)
5886 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5889 return WINED3D_OK;
5892 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5893 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5894 struct WineD3DRectPatch *patch;
5895 GLenum old_primitive_type;
5896 unsigned int i;
5897 struct list *e;
5898 BOOL found;
5899 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5901 if(!(Handle || pRectPatchInfo)) {
5902 /* TODO: Write a test for the return value, thus the FIXME */
5903 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5904 return WINED3DERR_INVALIDCALL;
5907 if(Handle) {
5908 i = PATCHMAP_HASHFUNC(Handle);
5909 found = FALSE;
5910 LIST_FOR_EACH(e, &This->patches[i]) {
5911 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5912 if(patch->Handle == Handle) {
5913 found = TRUE;
5914 break;
5918 if(!found) {
5919 TRACE("Patch does not exist. Creating a new one\n");
5920 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5921 patch->Handle = Handle;
5922 list_add_head(&This->patches[i], &patch->entry);
5923 } else {
5924 TRACE("Found existing patch %p\n", patch);
5926 } else {
5927 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5928 * attributes we have to tesselate, read back, and draw. This needs a patch
5929 * management structure instance. Create one.
5931 * A possible improvement is to check if a vertex shader is used, and if not directly
5932 * draw the patch.
5934 FIXME("Drawing an uncached patch. This is slow\n");
5935 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5938 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5939 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5940 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5941 HRESULT hr;
5942 TRACE("Tesselation density or patch info changed, retesselating\n");
5944 if(pRectPatchInfo) {
5945 patch->RectPatchInfo = *pRectPatchInfo;
5947 patch->numSegs[0] = pNumSegs[0];
5948 patch->numSegs[1] = pNumSegs[1];
5949 patch->numSegs[2] = pNumSegs[2];
5950 patch->numSegs[3] = pNumSegs[3];
5952 hr = tesselate_rectpatch(This, patch);
5953 if(FAILED(hr)) {
5954 WARN("Patch tesselation failed\n");
5956 /* Do not release the handle to store the params of the patch */
5957 if(!Handle) {
5958 HeapFree(GetProcessHeap(), 0, patch);
5960 return hr;
5964 This->currentPatch = patch;
5965 old_primitive_type = This->stateBlock->gl_primitive_type;
5966 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5967 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5968 This->stateBlock->gl_primitive_type = old_primitive_type;
5969 This->currentPatch = NULL;
5971 /* Destroy uncached patches */
5972 if(!Handle) {
5973 HeapFree(GetProcessHeap(), 0, patch->mem);
5974 HeapFree(GetProcessHeap(), 0, patch);
5976 return WINED3D_OK;
5979 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5980 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5981 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5982 FIXME("(%p) : Stub\n", This);
5983 return WINED3D_OK;
5986 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5987 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5988 int i;
5989 struct WineD3DRectPatch *patch;
5990 struct list *e;
5991 TRACE("(%p) Handle(%d)\n", This, Handle);
5993 i = PATCHMAP_HASHFUNC(Handle);
5994 LIST_FOR_EACH(e, &This->patches[i]) {
5995 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5996 if(patch->Handle == Handle) {
5997 TRACE("Deleting patch %p\n", patch);
5998 list_remove(&patch->entry);
5999 HeapFree(GetProcessHeap(), 0, patch->mem);
6000 HeapFree(GetProcessHeap(), 0, patch);
6001 return WINED3D_OK;
6005 /* TODO: Write a test for the return value */
6006 FIXME("Attempt to destroy nonexistent patch\n");
6007 return WINED3DERR_INVALIDCALL;
6010 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6011 HRESULT hr;
6012 IWineD3DSwapChain *swapchain;
6014 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6015 if (SUCCEEDED(hr)) {
6016 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6017 return swapchain;
6020 return NULL;
6023 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
6024 const WINED3DRECT *rect, const float color[4])
6026 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6027 struct wined3d_context *context;
6028 IWineD3DSwapChain *swapchain;
6030 swapchain = get_swapchain(surface);
6031 if (swapchain) {
6032 GLenum buffer;
6034 TRACE("Surface %p is onscreen\n", surface);
6036 context = ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6037 ENTER_GL();
6038 context_bind_fbo(context, GL_FRAMEBUFFER_EXT, NULL);
6039 buffer = surface_get_gl_buffer(surface, swapchain);
6040 glDrawBuffer(buffer);
6041 checkGLcall("glDrawBuffer()");
6042 } else {
6043 TRACE("Surface %p is offscreen\n", surface);
6045 context = ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6046 ENTER_GL();
6047 context_bind_fbo(context, GL_FRAMEBUFFER_EXT, &context->dst_fbo);
6048 context_attach_surface_fbo(context, GL_FRAMEBUFFER_EXT, 0, surface);
6049 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER_EXT, NULL, FALSE);
6052 if (rect) {
6053 glEnable(GL_SCISSOR_TEST);
6054 if(!swapchain) {
6055 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6056 } else {
6057 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6058 rect->x2 - rect->x1, rect->y2 - rect->y1);
6060 checkGLcall("glScissor");
6061 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6062 } else {
6063 glDisable(GL_SCISSOR_TEST);
6065 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6067 glDisable(GL_BLEND);
6068 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6070 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6071 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6073 glClearColor(color[0], color[1], color[2], color[3]);
6074 glClear(GL_COLOR_BUFFER_BIT);
6075 checkGLcall("glClear");
6077 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6078 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6079 glDrawBuffer(GL_BACK);
6080 checkGLcall("glDrawBuffer()");
6083 LEAVE_GL();
6086 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6087 unsigned int r, g, b, a;
6088 DWORD ret;
6090 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6091 destfmt == WINED3DFMT_R8G8B8)
6092 return color;
6094 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6096 a = (color & 0xff000000) >> 24;
6097 r = (color & 0x00ff0000) >> 16;
6098 g = (color & 0x0000ff00) >> 8;
6099 b = (color & 0x000000ff) >> 0;
6101 switch(destfmt)
6103 case WINED3DFMT_R5G6B5:
6104 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6105 r = (r * 32) / 256;
6106 g = (g * 64) / 256;
6107 b = (b * 32) / 256;
6108 ret = r << 11;
6109 ret |= g << 5;
6110 ret |= b;
6111 TRACE("Returning %08x\n", ret);
6112 return ret;
6114 case WINED3DFMT_X1R5G5B5:
6115 case WINED3DFMT_A1R5G5B5:
6116 a = (a * 2) / 256;
6117 r = (r * 32) / 256;
6118 g = (g * 32) / 256;
6119 b = (b * 32) / 256;
6120 ret = a << 15;
6121 ret |= r << 10;
6122 ret |= g << 5;
6123 ret |= b << 0;
6124 TRACE("Returning %08x\n", ret);
6125 return ret;
6127 case WINED3DFMT_A8_UNORM:
6128 TRACE("Returning %08x\n", a);
6129 return a;
6131 case WINED3DFMT_X4R4G4B4:
6132 case WINED3DFMT_A4R4G4B4:
6133 a = (a * 16) / 256;
6134 r = (r * 16) / 256;
6135 g = (g * 16) / 256;
6136 b = (b * 16) / 256;
6137 ret = a << 12;
6138 ret |= r << 8;
6139 ret |= g << 4;
6140 ret |= b << 0;
6141 TRACE("Returning %08x\n", ret);
6142 return ret;
6144 case WINED3DFMT_R3G3B2:
6145 r = (r * 8) / 256;
6146 g = (g * 8) / 256;
6147 b = (b * 4) / 256;
6148 ret = r << 5;
6149 ret |= g << 2;
6150 ret |= b << 0;
6151 TRACE("Returning %08x\n", ret);
6152 return ret;
6154 case WINED3DFMT_X8B8G8R8:
6155 case WINED3DFMT_R8G8B8A8_UNORM:
6156 ret = a << 24;
6157 ret |= b << 16;
6158 ret |= g << 8;
6159 ret |= r << 0;
6160 TRACE("Returning %08x\n", ret);
6161 return ret;
6163 case WINED3DFMT_A2R10G10B10:
6164 a = (a * 4) / 256;
6165 r = (r * 1024) / 256;
6166 g = (g * 1024) / 256;
6167 b = (b * 1024) / 256;
6168 ret = a << 30;
6169 ret |= r << 20;
6170 ret |= g << 10;
6171 ret |= b << 0;
6172 TRACE("Returning %08x\n", ret);
6173 return ret;
6175 case WINED3DFMT_R10G10B10A2_UNORM:
6176 a = (a * 4) / 256;
6177 r = (r * 1024) / 256;
6178 g = (g * 1024) / 256;
6179 b = (b * 1024) / 256;
6180 ret = a << 30;
6181 ret |= b << 20;
6182 ret |= g << 10;
6183 ret |= r << 0;
6184 TRACE("Returning %08x\n", ret);
6185 return ret;
6187 default:
6188 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6189 return 0;
6193 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6194 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6195 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6196 WINEDDBLTFX BltFx;
6197 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6199 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6200 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6201 return WINED3DERR_INVALIDCALL;
6204 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6205 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
6206 color_fill_fbo(iface, pSurface, pRect, c);
6207 return WINED3D_OK;
6208 } else {
6209 /* Just forward this to the DirectDraw blitting engine */
6210 memset(&BltFx, 0, sizeof(BltFx));
6211 BltFx.dwSize = sizeof(BltFx);
6212 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
6213 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6214 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
6218 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
6219 IWineD3DRendertargetView *rendertarget_view, const float color[4])
6221 IWineD3DResource *resource;
6222 IWineD3DSurface *surface;
6223 HRESULT hr;
6225 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
6226 if (FAILED(hr))
6228 ERR("Failed to get resource, hr %#x\n", hr);
6229 return;
6232 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
6234 FIXME("Only supported on surface resources\n");
6235 IWineD3DResource_Release(resource);
6236 return;
6239 surface = (IWineD3DSurface *)resource;
6241 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6243 color_fill_fbo(iface, surface, NULL, color);
6245 else
6247 WINEDDBLTFX BltFx;
6248 WINED3DCOLOR c;
6250 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
6252 c = ((DWORD)(color[2] * 255.0f));
6253 c |= ((DWORD)(color[1] * 255.0f)) << 8;
6254 c |= ((DWORD)(color[0] * 255.0f)) << 16;
6255 c |= ((DWORD)(color[3] * 255.0f)) << 24;
6257 /* Just forward this to the DirectDraw blitting engine */
6258 memset(&BltFx, 0, sizeof(BltFx));
6259 BltFx.dwSize = sizeof(BltFx);
6260 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
6261 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
6262 if (FAILED(hr))
6264 ERR("Blt failed, hr %#x\n", hr);
6268 IWineD3DResource_Release(resource);
6271 /* rendertarget and depth stencil functions */
6272 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6273 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6275 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6276 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6277 return WINED3DERR_INVALIDCALL;
6280 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6281 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6282 /* Note inc ref on returned surface */
6283 if(*ppRenderTarget != NULL)
6284 IWineD3DSurface_AddRef(*ppRenderTarget);
6285 return WINED3D_OK;
6288 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6289 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6290 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6291 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6292 IWineD3DSwapChainImpl *Swapchain;
6293 HRESULT hr;
6295 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6297 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6298 if(hr != WINED3D_OK) {
6299 ERR("Can't get the swapchain\n");
6300 return hr;
6303 /* Make sure to release the swapchain */
6304 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6306 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6307 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6308 return WINED3DERR_INVALIDCALL;
6310 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6311 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6312 return WINED3DERR_INVALIDCALL;
6315 if(Swapchain->frontBuffer != Front) {
6316 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6318 if(Swapchain->frontBuffer)
6320 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6321 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
6323 Swapchain->frontBuffer = Front;
6325 if(Swapchain->frontBuffer) {
6326 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6327 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
6331 if(Back && !Swapchain->backBuffer) {
6332 /* We need memory for the back buffer array - only one back buffer this way */
6333 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6334 if(!Swapchain->backBuffer) {
6335 ERR("Out of memory\n");
6336 return E_OUTOFMEMORY;
6340 if(Swapchain->backBuffer[0] != Back) {
6341 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6343 /* What to do about the context here in the case of multithreading? Not sure.
6344 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6346 WARN("No active context?\n");
6348 ENTER_GL();
6349 if(!Swapchain->backBuffer[0]) {
6350 /* GL was told to draw to the front buffer at creation,
6351 * undo that
6353 glDrawBuffer(GL_BACK);
6354 checkGLcall("glDrawBuffer(GL_BACK)");
6355 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6356 Swapchain->presentParms.BackBufferCount = 1;
6357 } else if (!Back) {
6358 /* That makes problems - disable for now */
6359 /* glDrawBuffer(GL_FRONT); */
6360 checkGLcall("glDrawBuffer(GL_FRONT)");
6361 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6362 Swapchain->presentParms.BackBufferCount = 0;
6364 LEAVE_GL();
6366 if(Swapchain->backBuffer[0])
6368 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6369 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
6371 Swapchain->backBuffer[0] = Back;
6373 if(Swapchain->backBuffer[0]) {
6374 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6375 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
6376 } else {
6377 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6378 Swapchain->backBuffer = NULL;
6383 return WINED3D_OK;
6386 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6387 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6388 *ppZStencilSurface = This->stencilBufferTarget;
6389 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6391 if(*ppZStencilSurface != NULL) {
6392 /* Note inc ref on returned surface */
6393 IWineD3DSurface_AddRef(*ppZStencilSurface);
6394 return WINED3D_OK;
6395 } else {
6396 return WINED3DERR_NOTFOUND;
6400 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6401 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6403 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6404 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6405 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6406 struct wined3d_context *context;
6407 GLenum gl_filter;
6408 POINT offset = {0, 0};
6410 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6411 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6412 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6413 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6415 switch (filter) {
6416 case WINED3DTEXF_LINEAR:
6417 gl_filter = GL_LINEAR;
6418 break;
6420 default:
6421 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6422 case WINED3DTEXF_NONE:
6423 case WINED3DTEXF_POINT:
6424 gl_filter = GL_NEAREST;
6425 break;
6428 /* Attach src surface to src fbo */
6429 src_swapchain = get_swapchain(src_surface);
6430 dst_swapchain = get_swapchain(dst_surface);
6432 if (src_swapchain) context = ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6433 else if (dst_swapchain) context = ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6434 else context = ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6436 if (src_swapchain) {
6437 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6439 TRACE("Source surface %p is onscreen\n", src_surface);
6440 /* Make sure the drawable is up to date. In the offscreen case
6441 * attach_surface_fbo() implicitly takes care of this. */
6442 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6444 if(buffer == GL_FRONT) {
6445 RECT windowsize;
6446 UINT h;
6447 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6448 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6449 h = windowsize.bottom - windowsize.top;
6450 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6451 src_rect->y1 = offset.y + h - src_rect->y1;
6452 src_rect->y2 = offset.y + h - src_rect->y2;
6453 } else {
6454 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6455 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6458 ENTER_GL();
6459 context_bind_fbo(context, GL_READ_FRAMEBUFFER_EXT, NULL);
6460 glReadBuffer(buffer);
6461 checkGLcall("glReadBuffer()");
6462 } else {
6463 TRACE("Source surface %p is offscreen\n", src_surface);
6464 ENTER_GL();
6465 context_bind_fbo(context, GL_READ_FRAMEBUFFER_EXT, &context->src_fbo);
6466 context_attach_surface_fbo(context, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6467 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6468 checkGLcall("glReadBuffer()");
6469 context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER_EXT, NULL, FALSE);
6471 LEAVE_GL();
6473 /* Attach dst surface to dst fbo */
6474 if (dst_swapchain) {
6475 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6477 TRACE("Destination surface %p is onscreen\n", dst_surface);
6478 /* Make sure the drawable is up to date. In the offscreen case
6479 * attach_surface_fbo() implicitly takes care of this. */
6480 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6482 if(buffer == GL_FRONT) {
6483 RECT windowsize;
6484 UINT h;
6485 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6486 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6487 h = windowsize.bottom - windowsize.top;
6488 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6489 dst_rect->y1 = offset.y + h - dst_rect->y1;
6490 dst_rect->y2 = offset.y + h - dst_rect->y2;
6491 } else {
6492 /* Screen coords = window coords, surface height = window height */
6493 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6494 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6497 ENTER_GL();
6498 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER_EXT, NULL);
6499 glDrawBuffer(buffer);
6500 checkGLcall("glDrawBuffer()");
6501 } else {
6502 TRACE("Destination surface %p is offscreen\n", dst_surface);
6504 ENTER_GL();
6505 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER_EXT, &context->dst_fbo);
6506 context_attach_surface_fbo(context, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6507 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6508 checkGLcall("glDrawBuffer()");
6509 context_attach_depth_stencil_fbo(context, GL_DRAW_FRAMEBUFFER_EXT, NULL, FALSE);
6511 glDisable(GL_SCISSOR_TEST);
6512 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6514 if (flip) {
6515 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6516 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6517 checkGLcall("glBlitFramebuffer()");
6518 } else {
6519 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6520 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6521 checkGLcall("glBlitFramebuffer()");
6524 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6526 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6527 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6528 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6529 glDrawBuffer(GL_BACK);
6530 checkGLcall("glDrawBuffer()");
6532 LEAVE_GL();
6535 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6536 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6537 WINED3DVIEWPORT viewport;
6539 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6541 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6542 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6543 This, RenderTargetIndex, GL_LIMITS(buffers));
6544 return WINED3DERR_INVALIDCALL;
6547 /* MSDN says that null disables the render target
6548 but a device must always be associated with a render target
6549 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6551 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6552 FIXME("Trying to set render target 0 to NULL\n");
6553 return WINED3DERR_INVALIDCALL;
6555 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6556 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);
6557 return WINED3DERR_INVALIDCALL;
6560 /* If we are trying to set what we already have, don't bother */
6561 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6562 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6563 return WINED3D_OK;
6565 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6566 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6567 This->render_targets[RenderTargetIndex] = pRenderTarget;
6569 /* Render target 0 is special */
6570 if(RenderTargetIndex == 0) {
6571 /* Finally, reset the viewport as the MSDN states. */
6572 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6573 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6574 viewport.X = 0;
6575 viewport.Y = 0;
6576 viewport.MaxZ = 1.0f;
6577 viewport.MinZ = 0.0f;
6578 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6580 return WINED3D_OK;
6583 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6584 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6585 HRESULT hr = WINED3D_OK;
6586 IWineD3DSurface *tmp;
6588 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6590 if (pNewZStencil == This->stencilBufferTarget) {
6591 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6592 } else {
6593 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6594 * depending on the renter target implementation being used.
6595 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6596 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6597 * stencil buffer and incur an extra memory overhead
6598 ******************************************************/
6600 if (This->stencilBufferTarget) {
6601 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6602 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6603 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6604 } else {
6605 struct wined3d_context *context = ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6606 surface_load_ds_location(This->stencilBufferTarget, context, SFLAG_DS_OFFSCREEN);
6607 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6611 tmp = This->stencilBufferTarget;
6612 This->stencilBufferTarget = pNewZStencil;
6613 /* should we be calling the parent or the wined3d surface? */
6614 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6615 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6616 hr = WINED3D_OK;
6618 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6619 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6620 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6621 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6622 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6626 return hr;
6629 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6630 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6632 /* TODO: the use of Impl is deprecated. */
6633 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6634 WINED3DLOCKED_RECT lockedRect;
6636 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6638 /* some basic validation checks */
6639 if(This->cursorTexture) {
6640 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6641 ENTER_GL();
6642 glDeleteTextures(1, &This->cursorTexture);
6643 LEAVE_GL();
6644 This->cursorTexture = 0;
6647 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6648 This->haveHardwareCursor = TRUE;
6649 else
6650 This->haveHardwareCursor = FALSE;
6652 if(pCursorBitmap) {
6653 WINED3DLOCKED_RECT rect;
6655 /* MSDN: Cursor must be A8R8G8B8 */
6656 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format_desc->format)
6658 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6659 return WINED3DERR_INVALIDCALL;
6662 /* MSDN: Cursor must be smaller than the display mode */
6663 if(pSur->currentDesc.Width > This->ddraw_width ||
6664 pSur->currentDesc.Height > This->ddraw_height) {
6665 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);
6666 return WINED3DERR_INVALIDCALL;
6669 if (!This->haveHardwareCursor) {
6670 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6672 /* Do not store the surface's pointer because the application may
6673 * release it after setting the cursor image. Windows doesn't
6674 * addref the set surface, so we can't do this either without
6675 * creating circular refcount dependencies. Copy out the gl texture
6676 * instead.
6678 This->cursorWidth = pSur->currentDesc.Width;
6679 This->cursorHeight = pSur->currentDesc.Height;
6680 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6682 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION);
6683 char *mem, *bits = rect.pBits;
6684 GLint intfmt = glDesc->glInternal;
6685 GLint format = glDesc->glFormat;
6686 GLint type = glDesc->glType;
6687 INT height = This->cursorHeight;
6688 INT width = This->cursorWidth;
6689 INT bpp = glDesc->byte_count;
6690 DWORD sampler;
6691 INT i;
6693 /* Reformat the texture memory (pitch and width can be
6694 * different) */
6695 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6696 for(i = 0; i < height; i++)
6697 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6698 IWineD3DSurface_UnlockRect(pCursorBitmap);
6700 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6702 ENTER_GL();
6704 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6705 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6706 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6709 /* Make sure that a proper texture unit is selected */
6710 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6711 checkGLcall("glActiveTextureARB");
6712 sampler = This->rev_tex_unit_map[0];
6713 if (sampler != WINED3D_UNMAPPED_STAGE)
6715 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6717 /* Create a new cursor texture */
6718 glGenTextures(1, &This->cursorTexture);
6719 checkGLcall("glGenTextures");
6720 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6721 checkGLcall("glBindTexture");
6722 /* Copy the bitmap memory into the cursor texture */
6723 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6724 HeapFree(GetProcessHeap(), 0, mem);
6725 checkGLcall("glTexImage2D");
6727 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6728 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6729 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6732 LEAVE_GL();
6734 else
6736 FIXME("A cursor texture was not returned.\n");
6737 This->cursorTexture = 0;
6740 else
6742 /* Draw a hardware cursor */
6743 ICONINFO cursorInfo;
6744 HCURSOR cursor;
6745 /* Create and clear maskBits because it is not needed for
6746 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6747 * chunks. */
6748 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6749 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6750 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6751 WINED3DLOCK_NO_DIRTY_UPDATE |
6752 WINED3DLOCK_READONLY
6754 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6755 pSur->currentDesc.Height);
6757 cursorInfo.fIcon = FALSE;
6758 cursorInfo.xHotspot = XHotSpot;
6759 cursorInfo.yHotspot = YHotSpot;
6760 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6761 pSur->currentDesc.Height, 1,
6762 1, &maskBits);
6763 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6764 pSur->currentDesc.Height, 1,
6765 32, lockedRect.pBits);
6766 IWineD3DSurface_UnlockRect(pCursorBitmap);
6767 /* Create our cursor and clean up. */
6768 cursor = CreateIconIndirect(&cursorInfo);
6769 SetCursor(cursor);
6770 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6771 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6772 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6773 This->hardwareCursor = cursor;
6774 HeapFree(GetProcessHeap(), 0, maskBits);
6778 This->xHotSpot = XHotSpot;
6779 This->yHotSpot = YHotSpot;
6780 return WINED3D_OK;
6783 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6784 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6785 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6787 This->xScreenSpace = XScreenSpace;
6788 This->yScreenSpace = YScreenSpace;
6790 return;
6794 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6795 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6796 BOOL oldVisible = This->bCursorVisible;
6797 POINT pt;
6799 TRACE("(%p) : visible(%d)\n", This, bShow);
6802 * When ShowCursor is first called it should make the cursor appear at the OS's last
6803 * known cursor position. Because of this, some applications just repetitively call
6804 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6806 GetCursorPos(&pt);
6807 This->xScreenSpace = pt.x;
6808 This->yScreenSpace = pt.y;
6810 if (This->haveHardwareCursor) {
6811 This->bCursorVisible = bShow;
6812 if (bShow)
6813 SetCursor(This->hardwareCursor);
6814 else
6815 SetCursor(NULL);
6817 else
6819 if (This->cursorTexture)
6820 This->bCursorVisible = bShow;
6823 return oldVisible;
6826 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6827 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6828 IWineD3DResourceImpl *resource;
6829 TRACE("(%p) : state (%u)\n", This, This->state);
6831 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6832 switch (This->state) {
6833 case WINED3D_OK:
6834 return WINED3D_OK;
6835 case WINED3DERR_DEVICELOST:
6837 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6838 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6839 return WINED3DERR_DEVICENOTRESET;
6841 return WINED3DERR_DEVICELOST;
6843 case WINED3DERR_DRIVERINTERNALERROR:
6844 return WINED3DERR_DRIVERINTERNALERROR;
6847 /* Unknown state */
6848 return WINED3DERR_DRIVERINTERNALERROR;
6851 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6852 TRACE("checking resource %p for eviction\n", resource);
6853 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6854 TRACE("Evicting %p\n", resource);
6855 IWineD3DResource_UnLoad(resource);
6857 IWineD3DResource_Release(resource);
6858 return S_OK;
6861 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6862 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6863 TRACE("(%p)\n", This);
6865 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6866 return WINED3D_OK;
6869 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6871 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6873 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6874 if(surface->Flags & SFLAG_DIBSECTION) {
6875 /* Release the DC */
6876 SelectObject(surface->hDC, surface->dib.holdbitmap);
6877 DeleteDC(surface->hDC);
6878 /* Release the DIB section */
6879 DeleteObject(surface->dib.DIBsection);
6880 surface->dib.bitmap_data = NULL;
6881 surface->resource.allocatedMemory = NULL;
6882 surface->Flags &= ~SFLAG_DIBSECTION;
6884 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6885 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6886 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
6887 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
6888 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6889 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6890 } else {
6891 surface->pow2Width = surface->pow2Height = 1;
6892 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6893 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6895 surface->glRect.left = 0;
6896 surface->glRect.top = 0;
6897 surface->glRect.right = surface->pow2Width;
6898 surface->glRect.bottom = surface->pow2Height;
6900 if (surface->texture_name)
6902 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6903 ENTER_GL();
6904 glDeleteTextures(1, &surface->texture_name);
6905 LEAVE_GL();
6906 surface->texture_name = 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 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6969 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6970 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6971 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6974 ENTER_GL();
6975 if(This->depth_blt_texture) {
6976 glDeleteTextures(1, &This->depth_blt_texture);
6977 This->depth_blt_texture = 0;
6979 if (This->depth_blt_rb) {
6980 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
6981 This->depth_blt_rb = 0;
6982 This->depth_blt_rb_w = 0;
6983 This->depth_blt_rb_h = 0;
6985 LEAVE_GL();
6987 This->blitter->free_private(iface);
6988 This->frag_pipe->free_private(iface);
6989 This->shader_backend->shader_free_private(iface);
6991 ENTER_GL();
6992 for (i = 0; i < GL_LIMITS(textures); i++) {
6993 /* Textures are recreated below */
6994 glDeleteTextures(1, &This->dummyTextureName[i]);
6995 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
6996 This->dummyTextureName[i] = 0;
6998 LEAVE_GL();
7000 while(This->numContexts) {
7001 DestroyContext(This, This->contexts[0]);
7003 HeapFree(GetProcessHeap(), 0, swapchain->context);
7004 swapchain->context = NULL;
7005 swapchain->num_contexts = 0;
7008 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7009 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7010 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7011 HRESULT hr;
7012 IWineD3DSurfaceImpl *target;
7014 /* Recreate the primary swapchain's context */
7015 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7016 if(swapchain->backBuffer) {
7017 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7018 } else {
7019 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7021 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7022 &swapchain->presentParms);
7023 swapchain->num_contexts = 1;
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 if (This->d3d_initialized)
7323 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7324 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7325 This->render_targets[i] = NULL;
7328 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7329 This->stencilBufferTarget = NULL;
7333 break;
7335 case WINED3DRTYPE_TEXTURE:
7336 case WINED3DRTYPE_CUBETEXTURE:
7337 case WINED3DRTYPE_VOLUMETEXTURE:
7338 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7339 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7340 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7341 This->stateBlock->textures[counter] = NULL;
7343 if (This->updateStateBlock != This->stateBlock ){
7344 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7345 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7346 This->updateStateBlock->textures[counter] = NULL;
7350 break;
7351 case WINED3DRTYPE_VOLUME:
7352 /* TODO: nothing really? */
7353 break;
7354 case WINED3DRTYPE_BUFFER:
7356 int streamNumber;
7357 TRACE("Cleaning up stream pointers\n");
7359 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7360 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7361 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7363 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7364 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7365 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7366 This->updateStateBlock->streamSource[streamNumber] = 0;
7367 /* Set changed flag? */
7370 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) */
7371 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7372 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7373 This->stateBlock->streamSource[streamNumber] = 0;
7378 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7379 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7380 This->updateStateBlock->pIndexData = NULL;
7383 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7384 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7385 This->stateBlock->pIndexData = NULL;
7389 break;
7391 default:
7392 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7393 break;
7397 /* Remove the resource from the resourceStore */
7398 device_resource_remove(This, resource);
7400 TRACE("Resource released\n");
7404 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7405 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7406 IWineD3DResourceImpl *resource, *cursor;
7407 HRESULT ret;
7408 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7410 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7411 TRACE("enumerating resource %p\n", resource);
7412 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7413 ret = pCallback((IWineD3DResource *) resource, pData);
7414 if(ret == S_FALSE) {
7415 TRACE("Canceling enumeration\n");
7416 break;
7419 return WINED3D_OK;
7422 /**********************************************************
7423 * IWineD3DDevice VTbl follows
7424 **********************************************************/
7426 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7428 /*** IUnknown methods ***/
7429 IWineD3DDeviceImpl_QueryInterface,
7430 IWineD3DDeviceImpl_AddRef,
7431 IWineD3DDeviceImpl_Release,
7432 /*** IWineD3DDevice methods ***/
7433 IWineD3DDeviceImpl_GetParent,
7434 /*** Creation methods**/
7435 IWineD3DDeviceImpl_CreateBuffer,
7436 IWineD3DDeviceImpl_CreateVertexBuffer,
7437 IWineD3DDeviceImpl_CreateIndexBuffer,
7438 IWineD3DDeviceImpl_CreateStateBlock,
7439 IWineD3DDeviceImpl_CreateSurface,
7440 IWineD3DDeviceImpl_CreateRendertargetView,
7441 IWineD3DDeviceImpl_CreateTexture,
7442 IWineD3DDeviceImpl_CreateVolumeTexture,
7443 IWineD3DDeviceImpl_CreateVolume,
7444 IWineD3DDeviceImpl_CreateCubeTexture,
7445 IWineD3DDeviceImpl_CreateQuery,
7446 IWineD3DDeviceImpl_CreateSwapChain,
7447 IWineD3DDeviceImpl_CreateVertexDeclaration,
7448 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7449 IWineD3DDeviceImpl_CreateVertexShader,
7450 IWineD3DDeviceImpl_CreatePixelShader,
7451 IWineD3DDeviceImpl_CreatePalette,
7452 /*** Odd functions **/
7453 IWineD3DDeviceImpl_Init3D,
7454 IWineD3DDeviceImpl_InitGDI,
7455 IWineD3DDeviceImpl_Uninit3D,
7456 IWineD3DDeviceImpl_UninitGDI,
7457 IWineD3DDeviceImpl_SetMultithreaded,
7458 IWineD3DDeviceImpl_EvictManagedResources,
7459 IWineD3DDeviceImpl_GetAvailableTextureMem,
7460 IWineD3DDeviceImpl_GetBackBuffer,
7461 IWineD3DDeviceImpl_GetCreationParameters,
7462 IWineD3DDeviceImpl_GetDeviceCaps,
7463 IWineD3DDeviceImpl_GetDirect3D,
7464 IWineD3DDeviceImpl_GetDisplayMode,
7465 IWineD3DDeviceImpl_SetDisplayMode,
7466 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7467 IWineD3DDeviceImpl_GetRasterStatus,
7468 IWineD3DDeviceImpl_GetSwapChain,
7469 IWineD3DDeviceImpl_Reset,
7470 IWineD3DDeviceImpl_SetDialogBoxMode,
7471 IWineD3DDeviceImpl_SetCursorProperties,
7472 IWineD3DDeviceImpl_SetCursorPosition,
7473 IWineD3DDeviceImpl_ShowCursor,
7474 IWineD3DDeviceImpl_TestCooperativeLevel,
7475 /*** Getters and setters **/
7476 IWineD3DDeviceImpl_SetClipPlane,
7477 IWineD3DDeviceImpl_GetClipPlane,
7478 IWineD3DDeviceImpl_SetClipStatus,
7479 IWineD3DDeviceImpl_GetClipStatus,
7480 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7481 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7482 IWineD3DDeviceImpl_SetDepthStencilSurface,
7483 IWineD3DDeviceImpl_GetDepthStencilSurface,
7484 IWineD3DDeviceImpl_SetGammaRamp,
7485 IWineD3DDeviceImpl_GetGammaRamp,
7486 IWineD3DDeviceImpl_SetIndices,
7487 IWineD3DDeviceImpl_GetIndices,
7488 IWineD3DDeviceImpl_SetBaseVertexIndex,
7489 IWineD3DDeviceImpl_GetBaseVertexIndex,
7490 IWineD3DDeviceImpl_SetLight,
7491 IWineD3DDeviceImpl_GetLight,
7492 IWineD3DDeviceImpl_SetLightEnable,
7493 IWineD3DDeviceImpl_GetLightEnable,
7494 IWineD3DDeviceImpl_SetMaterial,
7495 IWineD3DDeviceImpl_GetMaterial,
7496 IWineD3DDeviceImpl_SetNPatchMode,
7497 IWineD3DDeviceImpl_GetNPatchMode,
7498 IWineD3DDeviceImpl_SetPaletteEntries,
7499 IWineD3DDeviceImpl_GetPaletteEntries,
7500 IWineD3DDeviceImpl_SetPixelShader,
7501 IWineD3DDeviceImpl_GetPixelShader,
7502 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7503 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7504 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7505 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7506 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7507 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7508 IWineD3DDeviceImpl_SetRenderState,
7509 IWineD3DDeviceImpl_GetRenderState,
7510 IWineD3DDeviceImpl_SetRenderTarget,
7511 IWineD3DDeviceImpl_GetRenderTarget,
7512 IWineD3DDeviceImpl_SetFrontBackBuffers,
7513 IWineD3DDeviceImpl_SetSamplerState,
7514 IWineD3DDeviceImpl_GetSamplerState,
7515 IWineD3DDeviceImpl_SetScissorRect,
7516 IWineD3DDeviceImpl_GetScissorRect,
7517 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7518 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7519 IWineD3DDeviceImpl_SetStreamSource,
7520 IWineD3DDeviceImpl_GetStreamSource,
7521 IWineD3DDeviceImpl_SetStreamSourceFreq,
7522 IWineD3DDeviceImpl_GetStreamSourceFreq,
7523 IWineD3DDeviceImpl_SetTexture,
7524 IWineD3DDeviceImpl_GetTexture,
7525 IWineD3DDeviceImpl_SetTextureStageState,
7526 IWineD3DDeviceImpl_GetTextureStageState,
7527 IWineD3DDeviceImpl_SetTransform,
7528 IWineD3DDeviceImpl_GetTransform,
7529 IWineD3DDeviceImpl_SetVertexDeclaration,
7530 IWineD3DDeviceImpl_GetVertexDeclaration,
7531 IWineD3DDeviceImpl_SetVertexShader,
7532 IWineD3DDeviceImpl_GetVertexShader,
7533 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7534 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7535 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7536 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7537 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7538 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7539 IWineD3DDeviceImpl_SetViewport,
7540 IWineD3DDeviceImpl_GetViewport,
7541 IWineD3DDeviceImpl_MultiplyTransform,
7542 IWineD3DDeviceImpl_ValidateDevice,
7543 IWineD3DDeviceImpl_ProcessVertices,
7544 /*** State block ***/
7545 IWineD3DDeviceImpl_BeginStateBlock,
7546 IWineD3DDeviceImpl_EndStateBlock,
7547 /*** Scene management ***/
7548 IWineD3DDeviceImpl_BeginScene,
7549 IWineD3DDeviceImpl_EndScene,
7550 IWineD3DDeviceImpl_Present,
7551 IWineD3DDeviceImpl_Clear,
7552 IWineD3DDeviceImpl_ClearRendertargetView,
7553 /*** Drawing ***/
7554 IWineD3DDeviceImpl_SetPrimitiveType,
7555 IWineD3DDeviceImpl_GetPrimitiveType,
7556 IWineD3DDeviceImpl_DrawPrimitive,
7557 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7558 IWineD3DDeviceImpl_DrawPrimitiveUP,
7559 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7560 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7561 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7562 IWineD3DDeviceImpl_DrawRectPatch,
7563 IWineD3DDeviceImpl_DrawTriPatch,
7564 IWineD3DDeviceImpl_DeletePatch,
7565 IWineD3DDeviceImpl_ColorFill,
7566 IWineD3DDeviceImpl_UpdateTexture,
7567 IWineD3DDeviceImpl_UpdateSurface,
7568 IWineD3DDeviceImpl_GetFrontBufferData,
7569 /*** object tracking ***/
7570 IWineD3DDeviceImpl_EnumResources
7573 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7574 WINED3DRS_ALPHABLENDENABLE ,
7575 WINED3DRS_ALPHAFUNC ,
7576 WINED3DRS_ALPHAREF ,
7577 WINED3DRS_ALPHATESTENABLE ,
7578 WINED3DRS_BLENDOP ,
7579 WINED3DRS_COLORWRITEENABLE ,
7580 WINED3DRS_DESTBLEND ,
7581 WINED3DRS_DITHERENABLE ,
7582 WINED3DRS_FILLMODE ,
7583 WINED3DRS_FOGDENSITY ,
7584 WINED3DRS_FOGEND ,
7585 WINED3DRS_FOGSTART ,
7586 WINED3DRS_LASTPIXEL ,
7587 WINED3DRS_SHADEMODE ,
7588 WINED3DRS_SRCBLEND ,
7589 WINED3DRS_STENCILENABLE ,
7590 WINED3DRS_STENCILFAIL ,
7591 WINED3DRS_STENCILFUNC ,
7592 WINED3DRS_STENCILMASK ,
7593 WINED3DRS_STENCILPASS ,
7594 WINED3DRS_STENCILREF ,
7595 WINED3DRS_STENCILWRITEMASK ,
7596 WINED3DRS_STENCILZFAIL ,
7597 WINED3DRS_TEXTUREFACTOR ,
7598 WINED3DRS_WRAP0 ,
7599 WINED3DRS_WRAP1 ,
7600 WINED3DRS_WRAP2 ,
7601 WINED3DRS_WRAP3 ,
7602 WINED3DRS_WRAP4 ,
7603 WINED3DRS_WRAP5 ,
7604 WINED3DRS_WRAP6 ,
7605 WINED3DRS_WRAP7 ,
7606 WINED3DRS_ZENABLE ,
7607 WINED3DRS_ZFUNC ,
7608 WINED3DRS_ZWRITEENABLE
7611 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7612 WINED3DTSS_ALPHAARG0 ,
7613 WINED3DTSS_ALPHAARG1 ,
7614 WINED3DTSS_ALPHAARG2 ,
7615 WINED3DTSS_ALPHAOP ,
7616 WINED3DTSS_BUMPENVLOFFSET ,
7617 WINED3DTSS_BUMPENVLSCALE ,
7618 WINED3DTSS_BUMPENVMAT00 ,
7619 WINED3DTSS_BUMPENVMAT01 ,
7620 WINED3DTSS_BUMPENVMAT10 ,
7621 WINED3DTSS_BUMPENVMAT11 ,
7622 WINED3DTSS_COLORARG0 ,
7623 WINED3DTSS_COLORARG1 ,
7624 WINED3DTSS_COLORARG2 ,
7625 WINED3DTSS_COLOROP ,
7626 WINED3DTSS_RESULTARG ,
7627 WINED3DTSS_TEXCOORDINDEX ,
7628 WINED3DTSS_TEXTURETRANSFORMFLAGS
7631 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7632 WINED3DSAMP_ADDRESSU ,
7633 WINED3DSAMP_ADDRESSV ,
7634 WINED3DSAMP_ADDRESSW ,
7635 WINED3DSAMP_BORDERCOLOR ,
7636 WINED3DSAMP_MAGFILTER ,
7637 WINED3DSAMP_MINFILTER ,
7638 WINED3DSAMP_MIPFILTER ,
7639 WINED3DSAMP_MIPMAPLODBIAS ,
7640 WINED3DSAMP_MAXMIPLEVEL ,
7641 WINED3DSAMP_MAXANISOTROPY ,
7642 WINED3DSAMP_SRGBTEXTURE ,
7643 WINED3DSAMP_ELEMENTINDEX
7646 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7647 WINED3DRS_AMBIENT ,
7648 WINED3DRS_AMBIENTMATERIALSOURCE ,
7649 WINED3DRS_CLIPPING ,
7650 WINED3DRS_CLIPPLANEENABLE ,
7651 WINED3DRS_COLORVERTEX ,
7652 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7653 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7654 WINED3DRS_FOGDENSITY ,
7655 WINED3DRS_FOGEND ,
7656 WINED3DRS_FOGSTART ,
7657 WINED3DRS_FOGTABLEMODE ,
7658 WINED3DRS_FOGVERTEXMODE ,
7659 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7660 WINED3DRS_LIGHTING ,
7661 WINED3DRS_LOCALVIEWER ,
7662 WINED3DRS_MULTISAMPLEANTIALIAS ,
7663 WINED3DRS_MULTISAMPLEMASK ,
7664 WINED3DRS_NORMALIZENORMALS ,
7665 WINED3DRS_PATCHEDGESTYLE ,
7666 WINED3DRS_POINTSCALE_A ,
7667 WINED3DRS_POINTSCALE_B ,
7668 WINED3DRS_POINTSCALE_C ,
7669 WINED3DRS_POINTSCALEENABLE ,
7670 WINED3DRS_POINTSIZE ,
7671 WINED3DRS_POINTSIZE_MAX ,
7672 WINED3DRS_POINTSIZE_MIN ,
7673 WINED3DRS_POINTSPRITEENABLE ,
7674 WINED3DRS_RANGEFOGENABLE ,
7675 WINED3DRS_SPECULARMATERIALSOURCE ,
7676 WINED3DRS_TWEENFACTOR ,
7677 WINED3DRS_VERTEXBLEND ,
7678 WINED3DRS_CULLMODE ,
7679 WINED3DRS_FOGCOLOR
7682 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7683 WINED3DTSS_TEXCOORDINDEX ,
7684 WINED3DTSS_TEXTURETRANSFORMFLAGS
7687 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7688 WINED3DSAMP_DMAPOFFSET
7691 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7692 DWORD rep = This->StateTable[state].representative;
7693 struct wined3d_context *context;
7694 DWORD idx;
7695 BYTE shift;
7696 UINT i;
7698 for(i = 0; i < This->numContexts; i++) {
7699 context = This->contexts[i];
7700 if(isStateDirty(context, rep)) continue;
7702 context->dirtyArray[context->numDirtyEntries++] = rep;
7703 idx = rep >> 5;
7704 shift = rep & 0x1f;
7705 context->isStateDirty[idx] |= (1 << shift);
7709 void get_drawable_size_pbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7711 IWineD3DDeviceImpl *device = ((IWineD3DSurfaceImpl *)context->current_rt)->resource.wineD3DDevice;
7712 /* The drawable size of a pbuffer render target is the current pbuffer size. */
7713 *width = device->pbufferWidth;
7714 *height = device->pbufferHeight;
7717 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7719 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->current_rt;
7720 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7721 *width = surface->pow2Width;
7722 *height = surface->pow2Height;
7725 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7727 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->surface;
7728 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7729 * current context's drawable, which is the size of the back buffer of the swapchain
7730 * the active context belongs to. The back buffer of the swapchain is stored as the
7731 * surface the context belongs to. */
7732 *width = surface->currentDesc.Width;
7733 *height = surface->currentDesc.Height;