wined3d: Pass a proper format desc to resource_init() in IWineD3DDeviceImpl_CreateBuf...
[wine/wine-gecko.git] / dlls / wined3d / device.c
bloba7cb78875bb6d98e3d920bfc2a4791c80689eac6
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "config.h"
29 #include <stdio.h>
30 #ifdef HAVE_FLOAT_H
31 # include <float.h>
32 #endif
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION This->adapter->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* static function declarations */
55 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
57 /**********************************************************
58 * Global variable / Constants follow
59 **********************************************************/
60 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
62 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
63 * actually have the same values in GL and D3D. */
64 static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
66 switch(primitive_type)
68 case WINED3DPT_POINTLIST:
69 return GL_POINTS;
71 case WINED3DPT_LINELIST:
72 return GL_LINES;
74 case WINED3DPT_LINESTRIP:
75 return GL_LINE_STRIP;
77 case WINED3DPT_TRIANGLELIST:
78 return GL_TRIANGLES;
80 case WINED3DPT_TRIANGLESTRIP:
81 return GL_TRIANGLE_STRIP;
83 case WINED3DPT_TRIANGLEFAN:
84 return GL_TRIANGLE_FAN;
86 case WINED3DPT_LINELIST_ADJ:
87 return GL_LINES_ADJACENCY_ARB;
89 case WINED3DPT_LINESTRIP_ADJ:
90 return GL_LINE_STRIP_ADJACENCY_ARB;
92 case WINED3DPT_TRIANGLELIST_ADJ:
93 return GL_TRIANGLES_ADJACENCY_ARB;
95 case WINED3DPT_TRIANGLESTRIP_ADJ:
96 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
98 default:
99 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
100 return GL_NONE;
104 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
106 switch(primitive_type)
108 case GL_POINTS:
109 return WINED3DPT_POINTLIST;
111 case GL_LINES:
112 return WINED3DPT_LINELIST;
114 case GL_LINE_STRIP:
115 return WINED3DPT_LINESTRIP;
117 case GL_TRIANGLES:
118 return WINED3DPT_TRIANGLELIST;
120 case GL_TRIANGLE_STRIP:
121 return WINED3DPT_TRIANGLESTRIP;
123 case GL_TRIANGLE_FAN:
124 return WINED3DPT_TRIANGLEFAN;
126 case GL_LINES_ADJACENCY_ARB:
127 return WINED3DPT_LINELIST_ADJ;
129 case GL_LINE_STRIP_ADJACENCY_ARB:
130 return WINED3DPT_LINESTRIP_ADJ;
132 case GL_TRIANGLES_ADJACENCY_ARB:
133 return WINED3DPT_TRIANGLELIST_ADJ;
135 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
136 return WINED3DPT_TRIANGLESTRIP_ADJ;
138 default:
139 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
140 return WINED3DPT_UNDEFINED;
144 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
146 if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && usage_idx == 0)
147 *regnum = WINED3D_FFP_POSITION;
148 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
149 *regnum = WINED3D_FFP_BLENDWEIGHT;
150 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
151 *regnum = WINED3D_FFP_BLENDINDICES;
152 else if (usage == WINED3DDECLUSAGE_NORMAL && usage_idx == 0)
153 *regnum = WINED3D_FFP_NORMAL;
154 else if (usage == WINED3DDECLUSAGE_PSIZE && usage_idx == 0)
155 *regnum = WINED3D_FFP_PSIZE;
156 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 0)
157 *regnum = WINED3D_FFP_DIFFUSE;
158 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1)
159 *regnum = WINED3D_FFP_SPECULAR;
160 else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
161 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
162 else
164 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
165 *regnum = ~0U;
166 return FALSE;
169 return TRUE;
172 void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
173 BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
175 /* We need to deal with frequency data! */
176 IWineD3DVertexDeclarationImpl *declaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
177 UINT stream_count = This->stateBlock->streamIsUP ? 0 : declaration->num_streams;
178 const DWORD *streams = declaration->streams;
179 unsigned int i;
181 memset(stream_info, 0, sizeof(*stream_info));
183 /* Check for transformed vertices, disable vertex shader if present. */
184 stream_info->position_transformed = declaration->position_transformed;
185 if (declaration->position_transformed) use_vshader = FALSE;
187 /* Translate the declaration into strided data. */
188 for (i = 0; i < declaration->element_count; ++i)
190 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
191 GLuint buffer_object = 0;
192 const BYTE *data = NULL;
193 BOOL stride_used;
194 unsigned int idx;
195 DWORD stride;
197 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
198 element, i + 1, declaration->element_count);
200 if (!This->stateBlock->streamSource[element->input_slot]) continue;
202 stride = This->stateBlock->streamStride[element->input_slot];
203 if (This->stateBlock->streamIsUP)
205 TRACE("Stream %u is UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
206 buffer_object = 0;
207 data = (BYTE *)This->stateBlock->streamSource[element->input_slot];
209 else
211 TRACE("Stream %u isn't UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
212 data = buffer_get_memory(This->stateBlock->streamSource[element->input_slot], 0, &buffer_object);
214 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
215 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
216 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
217 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
218 * not, drawStridedSlow is needed, including a vertex buffer path. */
219 if (This->stateBlock->loadBaseVertexIndex < 0)
221 WARN("loadBaseVertexIndex is < 0 (%d), not using vbos\n", This->stateBlock->loadBaseVertexIndex);
222 buffer_object = 0;
223 data = buffer_get_sysmem((struct wined3d_buffer *)This->stateBlock->streamSource[element->input_slot]);
224 if ((UINT_PTR)data < -This->stateBlock->loadBaseVertexIndex * stride)
226 FIXME("System memory vertex data load offset is negative!\n");
230 if (fixup)
232 if (buffer_object) *fixup = TRUE;
233 else if (*fixup && !use_vshader
234 && (element->usage == WINED3DDECLUSAGE_COLOR
235 || element->usage == WINED3DDECLUSAGE_POSITIONT))
237 static BOOL warned = FALSE;
238 if (!warned)
240 /* This may be bad with the fixed function pipeline. */
241 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
242 warned = TRUE;
247 data += element->offset;
249 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
251 if (use_vshader)
253 if (element->output_slot == ~0U)
255 /* TODO: Assuming vertexdeclarations are usually used with the
256 * same or a similar shader, it might be worth it to store the
257 * last used output slot and try that one first. */
258 stride_used = vshader_get_input(This->stateBlock->vertexShader,
259 element->usage, element->usage_idx, &idx);
261 else
263 idx = element->output_slot;
264 stride_used = TRUE;
267 else
269 if (!element->ffp_valid)
271 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
272 debug_d3dformat(element->format_desc->format), debug_d3ddeclusage(element->usage));
273 stride_used = FALSE;
275 else
277 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
281 if (stride_used)
283 TRACE("Load %s array %u [usage %s, usage_idx %u, "
284 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
285 use_vshader ? "shader": "fixed function", idx,
286 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
287 element->offset, stride, debug_d3dformat(element->format_desc->format), buffer_object);
289 stream_info->elements[idx].format_desc = element->format_desc;
290 stream_info->elements[idx].stride = stride;
291 stream_info->elements[idx].data = data;
292 stream_info->elements[idx].stream_idx = element->input_slot;
293 stream_info->elements[idx].buffer_object = buffer_object;
295 if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA) && element->format_desc->format == WINED3DFMT_A8R8G8B8)
297 stream_info->swizzle_map |= 1 << idx;
299 stream_info->use_map |= 1 << idx;
303 /* Now call PreLoad on all the vertex buffers. In the very rare case
304 * that the buffers stopps converting PreLoad will dirtify the VDECL again.
305 * The vertex buffer can now use the strided structure in the device instead of finding its
306 * own again.
308 * NULL streams won't be recorded in the array, UP streams won't be either. A stream is only
309 * once in there. */
310 for (i = 0; i < stream_count; ++i)
312 IWineD3DBuffer *vb = This->stateBlock->streamSource[streams[i]];
313 if (vb) IWineD3DBuffer_PreLoad(vb);
317 static void stream_info_element_from_strided(IWineD3DDeviceImpl *This,
318 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
320 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(strided->format, &This->adapter->gl_info);
321 e->format_desc = format_desc;
322 e->stride = strided->dwStride;
323 e->data = strided->lpData;
324 e->stream_idx = 0;
325 e->buffer_object = 0;
328 void device_stream_info_from_strided(IWineD3DDeviceImpl *This,
329 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
331 unsigned int i;
333 memset(stream_info, 0, sizeof(*stream_info));
335 if (strided->position.lpData)
336 stream_info_element_from_strided(This, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
337 if (strided->normal.lpData)
338 stream_info_element_from_strided(This, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
339 if (strided->diffuse.lpData)
340 stream_info_element_from_strided(This, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
341 if (strided->specular.lpData)
342 stream_info_element_from_strided(This, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
344 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
346 if (strided->texCoords[i].lpData)
347 stream_info_element_from_strided(This, &strided->texCoords[i],
348 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
351 stream_info->position_transformed = strided->position_transformed;
353 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
355 if (!stream_info->elements[i].format_desc) continue;
357 if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA) && stream_info->elements[i].format_desc->format == WINED3DFMT_A8R8G8B8)
359 stream_info->swizzle_map |= 1 << i;
361 stream_info->use_map |= 1 << i;
365 /**********************************************************
366 * IUnknown parts follows
367 **********************************************************/
369 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
371 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
373 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
374 if (IsEqualGUID(riid, &IID_IUnknown)
375 || IsEqualGUID(riid, &IID_IWineD3DBase)
376 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
377 IUnknown_AddRef(iface);
378 *ppobj = This;
379 return S_OK;
381 *ppobj = NULL;
382 return E_NOINTERFACE;
385 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
386 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
387 ULONG refCount = InterlockedIncrement(&This->ref);
389 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
390 return refCount;
393 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
395 ULONG refCount = InterlockedDecrement(&This->ref);
397 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
399 if (!refCount) {
400 UINT i;
402 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
403 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
404 This->multistate_funcs[i] = NULL;
407 /* TODO: Clean up all the surfaces and textures! */
408 /* NOTE: You must release the parent if the object was created via a callback
409 ** ***************************/
411 if (!list_empty(&This->resources)) {
412 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
413 dumpResources(&This->resources);
416 if(This->contexts) ERR("Context array not freed!\n");
417 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
418 This->haveHardwareCursor = FALSE;
420 IWineD3D_Release(This->wineD3D);
421 This->wineD3D = NULL;
422 HeapFree(GetProcessHeap(), 0, This);
423 TRACE("Freed device %p\n", This);
424 This = NULL;
426 return refCount;
429 /**********************************************************
430 * IWineD3DDevice implementation follows
431 **********************************************************/
432 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
433 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
434 *pParent = This->parent;
435 IUnknown_AddRef(This->parent);
436 return WINED3D_OK;
439 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface,
440 struct wined3d_buffer_desc *desc, const void *data, IUnknown *parent, IWineD3DBuffer **buffer)
442 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
443 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(WINED3DFMT_UNKNOWN, &This->adapter->gl_info);
444 struct wined3d_buffer *object;
445 HRESULT hr;
447 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
449 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
450 if (!object)
452 ERR("Failed to allocate memory\n");
453 return E_OUTOFMEMORY;
456 object->vtbl = &wined3d_buffer_vtbl;
457 object->desc = *desc;
459 FIXME("Ignoring access flags (pool)\n");
461 hr = resource_init(&object->resource, WINED3DRTYPE_BUFFER, This, desc->byte_width,
462 desc->usage, format_desc, WINED3DPOOL_MANAGED, parent);
463 if (FAILED(hr))
465 WARN("Failed to initialize resource, returning %#x\n", hr);
466 HeapFree(GetProcessHeap(), 0, object);
467 return hr;
469 object->buffer_type_hint = GL_ARRAY_BUFFER_ARB;
471 TRACE("Created resource %p\n", object);
473 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
475 TRACE("size %#x, usage=%#x, format %s, memory @ %p, iface @ %p\n", object->resource.size, object->resource.usage,
476 debug_d3dformat(object->resource.format_desc->format), object->resource.allocatedMemory, object);
478 if (data)
480 BYTE *ptr;
482 hr = IWineD3DBuffer_Map((IWineD3DBuffer *)object, 0, desc->byte_width, &ptr, 0);
483 if (FAILED(hr))
485 ERR("Failed to map buffer, hr %#x\n", hr);
486 IWineD3DBuffer_Release((IWineD3DBuffer *)object);
487 return hr;
490 memcpy(ptr, data, desc->byte_width);
492 hr = IWineD3DBuffer_Unmap((IWineD3DBuffer *)object);
493 if (FAILED(hr))
495 ERR("Failed to unmap buffer, hr %#x\n", hr);
496 IWineD3DBuffer_Release((IWineD3DBuffer *)object);
497 return hr;
501 *buffer = (IWineD3DBuffer *)object;
503 return WINED3D_OK;
506 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
507 DWORD FVF, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer, IUnknown *parent)
509 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
510 /* Dummy format for now */
511 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(WINED3DFMT_VERTEXDATA, &This->adapter->gl_info);
512 struct wined3d_buffer *object;
513 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
514 HRESULT hr;
515 BOOL conv;
517 if(Size == 0) {
518 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
519 *ppVertexBuffer = NULL;
520 return WINED3DERR_INVALIDCALL;
521 } else if(Pool == WINED3DPOOL_SCRATCH) {
522 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
523 * anyway, SCRATCH vertex buffers aren't usable anywhere
525 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
526 *ppVertexBuffer = NULL;
527 return WINED3DERR_INVALIDCALL;
530 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
531 if (!object)
533 ERR("Out of memory\n");
534 *ppVertexBuffer = NULL;
535 return WINED3DERR_OUTOFVIDEOMEMORY;
538 object->vtbl = &wined3d_buffer_vtbl;
539 hr = resource_init(&object->resource, WINED3DRTYPE_BUFFER, This, Size, Usage, format_desc, Pool, parent);
540 if (FAILED(hr))
542 WARN("Failed to initialize resource, returning %#x\n", hr);
543 HeapFree(GetProcessHeap(), 0, object);
544 *ppVertexBuffer = NULL;
545 return hr;
547 object->buffer_type_hint = GL_ARRAY_BUFFER_ARB;
549 TRACE("(%p) : Created resource %p\n", This, object);
551 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
553 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);
554 *ppVertexBuffer = (IWineD3DBuffer *)object;
556 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
557 * drawStridedFast (half-life 2).
559 * Basically converting the vertices in the buffer is quite expensive, and observations
560 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
561 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
563 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
564 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
565 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
566 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
567 * dx7 apps.
568 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
569 * more. In this call we can convert dx7 buffers too.
571 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
572 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
573 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
574 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
575 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
576 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
577 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
578 } else if(dxVersion <= 7 && conv) {
579 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
580 } else {
581 object->flags |= WINED3D_BUFFER_CREATEBO;
583 return WINED3D_OK;
586 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
587 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer, IUnknown *parent)
589 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
590 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(WINED3DFMT_UNKNOWN, &This->adapter->gl_info);
591 struct wined3d_buffer *object;
592 HRESULT hr;
594 TRACE("(%p) Creating index buffer\n", This);
596 /* Allocate the storage for the device */
597 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
598 if (!object)
600 ERR("Out of memory\n");
601 *ppIndexBuffer = NULL;
602 return WINED3DERR_OUTOFVIDEOMEMORY;
605 object->vtbl = &wined3d_buffer_vtbl;
606 hr = resource_init(&object->resource, WINED3DRTYPE_BUFFER, This, Length, Usage, format_desc, Pool, parent);
607 if (FAILED(hr))
609 WARN("Failed to initialize resource, returning %#x\n", hr);
610 HeapFree(GetProcessHeap(), 0, object);
611 *ppIndexBuffer = NULL;
612 return hr;
614 object->buffer_type_hint = GL_ELEMENT_ARRAY_BUFFER_ARB;
616 TRACE("(%p) : Created resource %p\n", This, object);
618 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
620 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
621 object->flags |= WINED3D_BUFFER_CREATEBO;
624 TRACE("(%p) : Len=%d, Use=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage,
625 Pool, object, object->resource.allocatedMemory);
626 *ppIndexBuffer = (IWineD3DBuffer *) object;
628 return WINED3D_OK;
631 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
633 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
634 IWineD3DStateBlockImpl *object;
635 unsigned int i, j;
636 HRESULT temp_result;
638 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
639 if(!object)
641 ERR("Out of memory\n");
642 *ppStateBlock = NULL;
643 return WINED3DERR_OUTOFVIDEOMEMORY;
646 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
647 object->wineD3DDevice = This;
648 object->parent = parent;
649 object->ref = 1;
650 object->blockType = Type;
652 *ppStateBlock = (IWineD3DStateBlock *)object;
654 for(i = 0; i < LIGHTMAP_SIZE; i++) {
655 list_init(&object->lightMap[i]);
658 temp_result = allocate_shader_constants(object);
659 if (FAILED(temp_result))
661 HeapFree(GetProcessHeap(), 0, object);
662 return temp_result;
665 /* Special case - Used during initialization to produce a placeholder stateblock
666 so other functions called can update a state block */
667 if (Type == WINED3DSBT_INIT || Type == WINED3DSBT_RECORDED)
669 /* Don't bother increasing the reference count otherwise a device will never
670 be freed due to circular dependencies */
671 return WINED3D_OK;
674 /* Otherwise, might as well set the whole state block to the appropriate values */
675 if (This->stateBlock != NULL)
676 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
677 else
678 memset(object->streamFreq, 1, sizeof(object->streamFreq));
680 /* Reset the ref and type after kludging it */
681 object->wineD3DDevice = This;
682 object->ref = 1;
683 object->blockType = Type;
685 TRACE("Updating changed flags appropriate for type %d\n", Type);
687 if (Type == WINED3DSBT_ALL) {
689 TRACE("ALL => Pretend everything has changed\n");
690 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
692 /* Lights are not part of the changed / set structure */
693 for(j = 0; j < LIGHTMAP_SIZE; j++) {
694 struct list *e;
695 LIST_FOR_EACH(e, &object->lightMap[j]) {
696 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
697 light->changed = TRUE;
698 light->enabledChanged = TRUE;
701 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
702 object->contained_render_states[j - 1] = j;
704 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
705 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
706 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
707 object->contained_transform_states[j - 1] = j;
709 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
710 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
711 object->contained_vs_consts_f[j] = j;
713 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
714 for(j = 0; j < MAX_CONST_I; j++) {
715 object->contained_vs_consts_i[j] = j;
717 object->num_contained_vs_consts_i = MAX_CONST_I;
718 for(j = 0; j < MAX_CONST_B; j++) {
719 object->contained_vs_consts_b[j] = j;
721 object->num_contained_vs_consts_b = MAX_CONST_B;
722 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
723 object->contained_ps_consts_f[j] = j;
725 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
726 for(j = 0; j < MAX_CONST_I; j++) {
727 object->contained_ps_consts_i[j] = j;
729 object->num_contained_ps_consts_i = MAX_CONST_I;
730 for(j = 0; j < MAX_CONST_B; j++) {
731 object->contained_ps_consts_b[j] = j;
733 object->num_contained_ps_consts_b = MAX_CONST_B;
734 for(i = 0; i < MAX_TEXTURES; i++) {
735 for (j = 0; j <= WINED3D_HIGHEST_TEXTURE_STATE; ++j)
737 object->contained_tss_states[object->num_contained_tss_states].stage = i;
738 object->contained_tss_states[object->num_contained_tss_states].state = j;
739 object->num_contained_tss_states++;
742 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
743 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
744 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
745 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
746 object->num_contained_sampler_states++;
750 for(i = 0; i < MAX_STREAMS; i++) {
751 if(object->streamSource[i]) {
752 IWineD3DBuffer_AddRef(object->streamSource[i]);
755 if(object->pIndexData) {
756 IWineD3DBuffer_AddRef(object->pIndexData);
758 if(object->vertexShader) {
759 IWineD3DVertexShader_AddRef(object->vertexShader);
761 if(object->pixelShader) {
762 IWineD3DPixelShader_AddRef(object->pixelShader);
765 } else if (Type == WINED3DSBT_PIXELSTATE) {
767 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
768 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
770 object->changed.pixelShader = TRUE;
772 /* Pixel Shader Constants */
773 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
774 object->contained_ps_consts_f[i] = i;
775 object->changed.pixelShaderConstantsF[i] = TRUE;
777 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
778 for (i = 0; i < MAX_CONST_B; ++i) {
779 object->contained_ps_consts_b[i] = i;
780 object->changed.pixelShaderConstantsB |= (1 << i);
782 object->num_contained_ps_consts_b = MAX_CONST_B;
783 for (i = 0; i < MAX_CONST_I; ++i) {
784 object->contained_ps_consts_i[i] = i;
785 object->changed.pixelShaderConstantsI |= (1 << i);
787 object->num_contained_ps_consts_i = MAX_CONST_I;
789 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
790 DWORD rs = SavedPixelStates_R[i];
791 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
792 object->contained_render_states[i] = rs;
794 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
795 for (j = 0; j < MAX_TEXTURES; j++) {
796 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
797 DWORD state = SavedPixelStates_T[i];
798 object->changed.textureState[j] |= 1 << state;
799 object->contained_tss_states[object->num_contained_tss_states].stage = j;
800 object->contained_tss_states[object->num_contained_tss_states].state = state;
801 object->num_contained_tss_states++;
804 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
805 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
806 DWORD state = SavedPixelStates_S[i];
807 object->changed.samplerState[j] |= 1 << state;
808 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
809 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
810 object->num_contained_sampler_states++;
813 if(object->pixelShader) {
814 IWineD3DPixelShader_AddRef(object->pixelShader);
817 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
818 * on them. This makes releasing the buffer easier
820 for(i = 0; i < MAX_STREAMS; i++) {
821 object->streamSource[i] = NULL;
823 object->pIndexData = NULL;
824 object->vertexShader = NULL;
826 } else if (Type == WINED3DSBT_VERTEXSTATE) {
828 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
829 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
831 object->changed.vertexShader = TRUE;
833 /* Vertex Shader Constants */
834 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
835 object->changed.vertexShaderConstantsF[i] = TRUE;
836 object->contained_vs_consts_f[i] = i;
838 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
839 for (i = 0; i < MAX_CONST_B; ++i) {
840 object->contained_vs_consts_b[i] = i;
841 object->changed.vertexShaderConstantsB |= (1 << i);
843 object->num_contained_vs_consts_b = MAX_CONST_B;
844 for (i = 0; i < MAX_CONST_I; ++i) {
845 object->contained_vs_consts_i[i] = i;
846 object->changed.vertexShaderConstantsI |= (1 << i);
848 object->num_contained_vs_consts_i = MAX_CONST_I;
849 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
850 DWORD rs = SavedVertexStates_R[i];
851 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
852 object->contained_render_states[i] = rs;
854 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
855 for (j = 0; j < MAX_TEXTURES; j++) {
856 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
857 DWORD state = SavedVertexStates_T[i];
858 object->changed.textureState[j] |= 1 << state;
859 object->contained_tss_states[object->num_contained_tss_states].stage = j;
860 object->contained_tss_states[object->num_contained_tss_states].state = state;
861 object->num_contained_tss_states++;
864 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
865 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
866 DWORD state = SavedVertexStates_S[i];
867 object->changed.samplerState[j] |= 1 << state;
868 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
869 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
870 object->num_contained_sampler_states++;
874 for(j = 0; j < LIGHTMAP_SIZE; j++) {
875 struct list *e;
876 LIST_FOR_EACH(e, &object->lightMap[j]) {
877 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
878 light->changed = TRUE;
879 light->enabledChanged = TRUE;
883 for(i = 0; i < MAX_STREAMS; i++) {
884 if(object->streamSource[i]) {
885 IWineD3DBuffer_AddRef(object->streamSource[i]);
888 if(object->vertexShader) {
889 IWineD3DVertexShader_AddRef(object->vertexShader);
891 object->pIndexData = NULL;
892 object->pixelShader = NULL;
893 } else {
894 FIXME("Unrecognized state block type %d\n", Type);
897 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
898 return WINED3D_OK;
901 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface,
902 UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level,
903 IWineD3DSurface **ppSurface, WINED3DRESOURCETYPE Type, DWORD Usage, WINED3DPOOL Pool,
904 WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, WINED3DSURFTYPE Impl, IUnknown *parent)
906 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
907 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
908 unsigned int Size = 1;
909 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(Format, &GLINFO_LOCATION);
910 UINT mul_4w, mul_4h;
911 HRESULT hr;
913 TRACE("(%p) Create surface\n",This);
915 if(MultisampleQuality > 0) {
916 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
917 MultisampleQuality=0;
920 /** FIXME: Check that the format is supported
921 * by the device.
922 *******************************/
924 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
925 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
926 * space!
927 *********************************/
928 mul_4w = (Width + 3) & ~3;
929 mul_4h = (Height + 3) & ~3;
930 if (WINED3DFMT_UNKNOWN == Format) {
931 Size = 0;
932 } else if (Format == WINED3DFMT_DXT1) {
933 /* DXT1 is half byte per pixel */
934 Size = (mul_4w * glDesc->byte_count * mul_4h) >> 1;
936 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
937 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
938 Format == WINED3DFMT_ATI2N) {
939 Size = (mul_4w * glDesc->byte_count * mul_4h);
940 } else {
941 /* The pitch is a multiple of 4 bytes */
942 Size = ((Width * glDesc->byte_count) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
943 Size *= Height;
946 if(glDesc->heightscale != 0.0) Size *= glDesc->heightscale;
948 /** Create and initialise the surface resource **/
949 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
950 if (!object)
952 ERR("Out of memory\n");
953 *ppSurface = NULL;
954 return WINED3DERR_OUTOFVIDEOMEMORY;
957 /* Look at the implementation and set the correct Vtable */
958 switch(Impl)
960 case SURFACE_OPENGL:
961 /* Check if a 3D adapter is available when creating gl surfaces */
962 if (!This->adapter)
964 ERR("OpenGL surfaces are not available without opengl\n");
965 HeapFree(GetProcessHeap(), 0, object);
966 return WINED3DERR_NOTAVAILABLE;
968 object->lpVtbl = &IWineD3DSurface_Vtbl;
969 break;
971 case SURFACE_GDI:
972 object->lpVtbl = &IWineGDISurface_Vtbl;
973 break;
975 default:
976 /* To be sure to catch this */
977 ERR("Unknown requested surface implementation %d!\n", Impl);
978 HeapFree(GetProcessHeap(), 0, object);
979 return WINED3DERR_INVALIDCALL;
982 hr = resource_init(&object->resource, WINED3DRTYPE_SURFACE, This, Size, Usage, glDesc, Pool, parent);
983 if (FAILED(hr))
985 WARN("Failed to initialize resource, returning %#x\n", hr);
986 HeapFree(GetProcessHeap(), 0, object);
987 *ppSurface = NULL;
988 return hr;
991 TRACE("(%p) : Created resource %p\n", This, object);
993 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
995 *ppSurface = (IWineD3DSurface *)object;
997 /* "Standalone" surface */
998 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
1000 object->currentDesc.Width = Width;
1001 object->currentDesc.Height = Height;
1002 object->currentDesc.MultiSampleType = MultiSample;
1003 object->currentDesc.MultiSampleQuality = MultisampleQuality;
1004 object->glDescription.level = Level;
1005 list_init(&object->overlays);
1007 /* Flags */
1008 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
1009 object->Flags |= Discard ? SFLAG_DISCARD : 0;
1010 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
1011 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
1013 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
1015 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
1016 * this function is too deep to need to care about things like this.
1017 * Levels need to be checked too, and possibly Type since they all affect what can be done.
1018 * ****************************************/
1019 switch(Pool) {
1020 case WINED3DPOOL_SCRATCH:
1021 if(!Lockable)
1022 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
1023 "which are mutually exclusive, setting lockable to TRUE\n");
1024 Lockable = TRUE;
1025 break;
1026 case WINED3DPOOL_SYSTEMMEM:
1027 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
1028 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
1029 case WINED3DPOOL_MANAGED:
1030 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
1031 "Usage of DYNAMIC which are mutually exclusive, not doing "
1032 "anything just telling you.\n");
1033 break;
1034 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
1035 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
1036 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
1037 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
1038 break;
1039 default:
1040 FIXME("(%p) Unknown pool %d\n", This, Pool);
1041 break;
1044 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
1045 FIXME("Trying to create a render target that isn't in the default pool\n");
1048 /* mark the texture as dirty so that it gets loaded first time around*/
1049 surface_add_dirty_rect(*ppSurface, NULL);
1050 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
1051 This, Width, Height, Format, debug_d3dformat(Format),
1052 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
1054 list_init(&object->renderbuffers);
1056 /* Call the private setup routine */
1057 hr = IWineD3DSurface_PrivateSetup((IWineD3DSurface *)object);
1058 if (FAILED(hr))
1060 ERR("Private setup failed, returning %#x\n", hr);
1061 IWineD3DSurface_Release(*ppSurface);
1062 *ppSurface = NULL;
1063 return hr;
1066 return hr;
1069 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
1070 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
1072 struct wined3d_rendertarget_view *object;
1074 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1075 if (!object)
1077 ERR("Failed to allocate memory\n");
1078 return E_OUTOFMEMORY;
1081 object->vtbl = &wined3d_rendertarget_view_vtbl;
1082 object->refcount = 1;
1083 IWineD3DResource_AddRef(resource);
1084 object->resource = resource;
1085 object->parent = parent;
1087 *rendertarget_view = (IWineD3DRendertargetView *)object;
1089 return WINED3D_OK;
1092 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
1093 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
1094 WINED3DPOOL Pool, IWineD3DTexture **ppTexture, IUnknown *parent)
1096 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1097 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
1098 IWineD3DTextureImpl *object;
1099 unsigned int i;
1100 UINT tmpW;
1101 UINT tmpH;
1102 HRESULT hr;
1103 unsigned int pow2Width;
1104 unsigned int pow2Height;
1106 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1107 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
1108 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
1110 /* TODO: It should only be possible to create textures for formats
1111 that are reported as supported */
1112 if (WINED3DFMT_UNKNOWN >= Format) {
1113 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1114 return WINED3DERR_INVALIDCALL;
1117 /* Non-power2 support */
1118 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO))
1120 pow2Width = Width;
1121 pow2Height = Height;
1123 else
1125 /* Find the nearest pow2 match */
1126 pow2Width = pow2Height = 1;
1127 while (pow2Width < Width) pow2Width <<= 1;
1128 while (pow2Height < Height) pow2Height <<= 1;
1130 if (pow2Width != Width || pow2Height != Height)
1132 if (Levels > 1)
1134 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
1135 return WINED3DERR_INVALIDCALL;
1137 Levels = 1;
1141 /* Calculate levels for mip mapping */
1142 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1144 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1146 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1147 return WINED3DERR_INVALIDCALL;
1150 if (Levels > 1)
1152 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1153 return WINED3DERR_INVALIDCALL;
1156 Levels = 1;
1158 else if (!Levels)
1160 Levels = wined3d_log2i(max(Width, Height)) + 1;
1161 TRACE("Calculated levels = %d\n", Levels);
1164 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1165 if (!object)
1167 ERR("Out of memory\n");
1168 *ppTexture = NULL;
1169 return WINED3DERR_OUTOFVIDEOMEMORY;
1172 object->lpVtbl = &IWineD3DTexture_Vtbl;
1173 hr = resource_init(&object->resource, WINED3DRTYPE_TEXTURE, This, 0, Usage, format_desc, Pool, parent);
1174 if (FAILED(hr))
1176 WARN("Failed to initialize resource, returning %#x\n", hr);
1177 HeapFree(GetProcessHeap(), 0, object);
1178 *ppTexture = NULL;
1179 return hr;
1182 TRACE("(%p) : Created resource %p\n", This, object);
1184 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1186 *ppTexture = (IWineD3DTexture *)object;
1188 basetexture_init(&object->baseTexture, Levels, Usage);
1190 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
1192 object->baseTexture.minMipLookup = minMipLookup;
1193 object->baseTexture.magLookup = magLookup;
1194 } else {
1195 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1196 object->baseTexture.magLookup = magLookup_noFilter;
1199 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1200 /* Precalculated scaling for 'faked' non power of two texture coords.
1201 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
1202 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
1203 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
1205 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (Width != pow2Width || Height != pow2Height)) {
1206 object->baseTexture.pow2Matrix[0] = 1.0;
1207 object->baseTexture.pow2Matrix[5] = 1.0;
1208 object->baseTexture.pow2Matrix[10] = 1.0;
1209 object->baseTexture.pow2Matrix[15] = 1.0;
1210 object->target = GL_TEXTURE_2D;
1211 object->cond_np2 = TRUE;
1212 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1213 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
1214 (Width != pow2Width || Height != pow2Height) &&
1215 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
1217 if ((Width != 1) || (Height != 1)) {
1218 object->baseTexture.pow2Matrix_identity = FALSE;
1221 object->baseTexture.pow2Matrix[0] = (float)Width;
1222 object->baseTexture.pow2Matrix[5] = (float)Height;
1223 object->baseTexture.pow2Matrix[10] = 1.0;
1224 object->baseTexture.pow2Matrix[15] = 1.0;
1225 object->target = GL_TEXTURE_RECTANGLE_ARB;
1226 object->cond_np2 = TRUE;
1227 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1228 } else {
1229 if ((Width != pow2Width) || (Height != pow2Height)) {
1230 object->baseTexture.pow2Matrix_identity = FALSE;
1231 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
1232 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
1233 } else {
1234 object->baseTexture.pow2Matrix[0] = 1.0;
1235 object->baseTexture.pow2Matrix[5] = 1.0;
1238 object->baseTexture.pow2Matrix[10] = 1.0;
1239 object->baseTexture.pow2Matrix[15] = 1.0;
1240 object->target = GL_TEXTURE_2D;
1241 object->cond_np2 = FALSE;
1243 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
1245 /* Generate all the surfaces */
1246 tmpW = Width;
1247 tmpH = Height;
1248 for (i = 0; i < object->baseTexture.levels; i++)
1250 /* use the callback to create the texture surface */
1251 hr = IWineD3DDeviceParent_CreateSurface(This->device_parent, parent, tmpW, tmpH, Format,
1252 Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i]);
1253 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1254 FIXME("Failed to create surface %p\n", object);
1255 /* clean up */
1256 object->surfaces[i] = NULL;
1257 IWineD3DTexture_Release((IWineD3DTexture *)object);
1259 *ppTexture = NULL;
1260 return hr;
1263 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1264 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1265 surface_set_texture_target(object->surfaces[i], object->target);
1266 /* calculate the next mipmap level */
1267 tmpW = max(1, tmpW >> 1);
1268 tmpH = max(1, tmpH >> 1);
1270 object->baseTexture.internal_preload = texture_internal_preload;
1272 TRACE("(%p) : Created texture %p\n", This, object);
1273 return WINED3D_OK;
1276 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1277 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
1278 WINED3DPOOL Pool, IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent)
1280 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1281 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
1282 IWineD3DVolumeTextureImpl *object;
1283 unsigned int i;
1284 UINT tmpW;
1285 UINT tmpH;
1286 UINT tmpD;
1287 HRESULT hr;
1289 /* TODO: It should only be possible to create textures for formats
1290 that are reported as supported */
1291 if (WINED3DFMT_UNKNOWN >= Format) {
1292 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1293 return WINED3DERR_INVALIDCALL;
1295 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1296 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
1297 return WINED3DERR_INVALIDCALL;
1300 /* Calculate levels for mip mapping */
1301 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1303 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1305 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1306 return WINED3DERR_INVALIDCALL;
1309 if (Levels > 1)
1311 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1312 return WINED3DERR_INVALIDCALL;
1315 Levels = 1;
1317 else if (!Levels)
1319 Levels = wined3d_log2i(max(max(Width, Height), Depth)) + 1;
1320 TRACE("Calculated levels = %d\n", Levels);
1323 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1324 if (!object)
1326 ERR("Out of memory\n");
1327 *ppVolumeTexture = NULL;
1328 return WINED3DERR_OUTOFVIDEOMEMORY;
1331 object->lpVtbl = &IWineD3DVolumeTexture_Vtbl;
1332 hr = resource_init(&object->resource, WINED3DRTYPE_VOLUMETEXTURE, This, 0, Usage, format_desc, Pool, parent);
1333 if (FAILED(hr))
1335 WARN("Failed to initialize resource, returning %#x\n", hr);
1336 HeapFree(GetProcessHeap(), 0, object);
1337 *ppVolumeTexture = NULL;
1338 return hr;
1341 TRACE("(%p) : Created resource %p\n", This, object);
1343 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1345 basetexture_init(&object->baseTexture, Levels, Usage);
1347 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1348 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1350 /* Is NP2 support for volumes needed? */
1351 object->baseTexture.pow2Matrix[ 0] = 1.0;
1352 object->baseTexture.pow2Matrix[ 5] = 1.0;
1353 object->baseTexture.pow2Matrix[10] = 1.0;
1354 object->baseTexture.pow2Matrix[15] = 1.0;
1356 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
1358 object->baseTexture.minMipLookup = minMipLookup;
1359 object->baseTexture.magLookup = magLookup;
1360 } else {
1361 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1362 object->baseTexture.magLookup = magLookup_noFilter;
1365 /* Generate all the surfaces */
1366 tmpW = Width;
1367 tmpH = Height;
1368 tmpD = Depth;
1370 for (i = 0; i < object->baseTexture.levels; i++)
1372 HRESULT hr;
1373 /* Create the volume */
1374 hr = IWineD3DDeviceParent_CreateVolume(This->device_parent, parent,
1375 tmpW, tmpH, tmpD, Format, Pool, Usage, &object->volumes[i]);
1376 if(FAILED(hr)) {
1377 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
1378 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
1379 *ppVolumeTexture = NULL;
1380 return hr;
1383 /* Set its container to this object */
1384 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1386 /* calculate the next mipmap level */
1387 tmpW = max(1, tmpW >> 1);
1388 tmpH = max(1, tmpH >> 1);
1389 tmpD = max(1, tmpD >> 1);
1391 object->baseTexture.internal_preload = volumetexture_internal_preload;
1393 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1394 TRACE("(%p) : Created volume texture %p\n", This, object);
1395 return WINED3D_OK;
1398 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1399 UINT Width, UINT Height, UINT Depth, DWORD Usage, WINED3DFORMAT Format,
1400 WINED3DPOOL Pool, IWineD3DVolume **ppVolume, IUnknown *parent)
1402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1403 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1404 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &GLINFO_LOCATION);
1405 HRESULT hr;
1407 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1408 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1409 return WINED3DERR_INVALIDCALL;
1412 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1413 if (!object)
1415 ERR("Out of memory\n");
1416 *ppVolume = NULL;
1417 return WINED3DERR_OUTOFVIDEOMEMORY;
1420 object->lpVtbl = &IWineD3DVolume_Vtbl;
1421 hr = resource_init(&object->resource, WINED3DRTYPE_VOLUME, This,
1422 Width * Height * Depth * format_desc->byte_count, Usage, format_desc, Pool, parent);
1423 if (FAILED(hr))
1425 WARN("Failed to initialize resource, returning %#x\n", hr);
1426 HeapFree(GetProcessHeap(), 0, object);
1427 *ppVolume = NULL;
1428 return hr;
1431 TRACE("(%p) : Created resource %p\n", This, object);
1433 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1435 *ppVolume = (IWineD3DVolume *)object;
1437 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1438 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1440 object->currentDesc.Width = Width;
1441 object->currentDesc.Height = Height;
1442 object->currentDesc.Depth = Depth;
1444 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1445 object->lockable = TRUE;
1446 object->locked = FALSE;
1447 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1448 object->dirty = TRUE;
1450 volume_add_dirty_box((IWineD3DVolume *)object, NULL);
1452 return WINED3D_OK;
1455 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface,
1456 UINT EdgeLength, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
1457 WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture, IUnknown *parent)
1459 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1460 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
1461 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1462 unsigned int i, j;
1463 UINT tmpW;
1464 HRESULT hr;
1465 unsigned int pow2EdgeLength;
1467 /* TODO: It should only be possible to create textures for formats
1468 that are reported as supported */
1469 if (WINED3DFMT_UNKNOWN >= Format) {
1470 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1471 return WINED3DERR_INVALIDCALL;
1474 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1475 WARN("(%p) : Tried to create not supported cube texture\n", This);
1476 return WINED3DERR_INVALIDCALL;
1479 /* Calculate levels for mip mapping */
1480 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1482 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1484 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1485 return WINED3DERR_INVALIDCALL;
1488 if (Levels > 1)
1490 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1491 return WINED3DERR_INVALIDCALL;
1494 Levels = 1;
1496 else if (!Levels)
1498 Levels = wined3d_log2i(EdgeLength) + 1;
1499 TRACE("Calculated levels = %d\n", Levels);
1502 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1503 if (!object)
1505 ERR("Out of memory\n");
1506 *ppCubeTexture = NULL;
1507 return WINED3DERR_OUTOFVIDEOMEMORY;
1510 object->lpVtbl = &IWineD3DCubeTexture_Vtbl;
1511 hr = resource_init(&object->resource, WINED3DRTYPE_CUBETEXTURE, This, 0, Usage, format_desc, Pool, parent);
1512 if (FAILED(hr))
1514 WARN("Failed to initialize resource, returning %#x\n", hr);
1515 HeapFree(GetProcessHeap(), 0, object);
1516 *ppCubeTexture = NULL;
1517 return hr;
1520 TRACE("(%p) : Created resource %p\n", This, object);
1522 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1524 basetexture_init(&object->baseTexture, Levels, Usage);
1526 TRACE("(%p) Create Cube Texture\n", This);
1528 /* Find the nearest pow2 match */
1529 pow2EdgeLength = 1;
1530 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1532 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || (EdgeLength == pow2EdgeLength)) {
1533 /* Precalculated scaling for 'faked' non power of two texture coords */
1534 object->baseTexture.pow2Matrix[ 0] = 1.0;
1535 object->baseTexture.pow2Matrix[ 5] = 1.0;
1536 object->baseTexture.pow2Matrix[10] = 1.0;
1537 object->baseTexture.pow2Matrix[15] = 1.0;
1538 } else {
1539 /* Precalculated scaling for 'faked' non power of two texture coords */
1540 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1541 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1542 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1543 object->baseTexture.pow2Matrix[15] = 1.0;
1544 object->baseTexture.pow2Matrix_identity = FALSE;
1547 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
1549 object->baseTexture.minMipLookup = minMipLookup;
1550 object->baseTexture.magLookup = magLookup;
1551 } else {
1552 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1553 object->baseTexture.magLookup = magLookup_noFilter;
1556 /* Generate all the surfaces */
1557 tmpW = EdgeLength;
1558 for (i = 0; i < object->baseTexture.levels; i++) {
1560 /* Create the 6 faces */
1561 for (j = 0; j < 6; j++) {
1562 static const GLenum cube_targets[6] = {
1563 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
1564 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
1565 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
1566 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
1567 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
1568 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
1571 hr = IWineD3DDeviceParent_CreateSurface(This->device_parent, parent, tmpW, tmpW,
1572 Format, Usage, Pool, i /* Level */, j, &object->surfaces[j][i]);
1573 if (FAILED(hr))
1575 FIXME("(%p) Failed to create surface\n",object);
1576 IWineD3DCubeTexture_Release((IWineD3DCubeTexture *)object);
1577 *ppCubeTexture = NULL;
1578 return hr;
1580 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1581 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1582 surface_set_texture_target(object->surfaces[j][i], cube_targets[j]);
1584 tmpW = max(1, tmpW >> 1);
1586 object->baseTexture.internal_preload = cubetexture_internal_preload;
1588 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1589 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1590 return WINED3D_OK;
1593 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1594 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1595 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1596 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1597 const IWineD3DQueryVtbl *vtable;
1599 /* Just a check to see if we support this type of query */
1600 switch(Type) {
1601 case WINED3DQUERYTYPE_OCCLUSION:
1602 TRACE("(%p) occlusion query\n", This);
1603 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1604 hr = WINED3D_OK;
1605 else
1606 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1608 vtable = &IWineD3DOcclusionQuery_Vtbl;
1609 break;
1611 case WINED3DQUERYTYPE_EVENT:
1612 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1613 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1614 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1616 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1618 vtable = &IWineD3DEventQuery_Vtbl;
1619 hr = WINED3D_OK;
1620 break;
1622 case WINED3DQUERYTYPE_VCACHE:
1623 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1624 case WINED3DQUERYTYPE_VERTEXSTATS:
1625 case WINED3DQUERYTYPE_TIMESTAMP:
1626 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1627 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1628 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1629 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1630 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1631 case WINED3DQUERYTYPE_PIXELTIMINGS:
1632 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1633 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1634 default:
1635 /* Use the base Query vtable until we have a special one for each query */
1636 vtable = &IWineD3DQuery_Vtbl;
1637 FIXME("(%p) Unhandled query type %d\n", This, Type);
1639 if(NULL == ppQuery || hr != WINED3D_OK) {
1640 return hr;
1643 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1644 if(!object)
1646 ERR("Out of memory\n");
1647 *ppQuery = NULL;
1648 return WINED3DERR_OUTOFVIDEOMEMORY;
1651 object->lpVtbl = vtable;
1652 object->type = Type;
1653 object->state = QUERY_CREATED;
1654 object->wineD3DDevice = This;
1655 object->parent = parent;
1656 object->ref = 1;
1658 *ppQuery = (IWineD3DQuery *)object;
1660 /* allocated the 'extended' data based on the type of query requested */
1661 switch(Type){
1662 case WINED3DQUERYTYPE_OCCLUSION:
1663 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1664 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1666 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1667 TRACE("(%p) Allocating data for an occlusion query\n", This);
1669 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1670 ENTER_GL();
1671 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1672 LEAVE_GL();
1673 break;
1675 case WINED3DQUERYTYPE_EVENT:
1676 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1677 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1679 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1680 ENTER_GL();
1681 if(GL_SUPPORT(APPLE_FENCE)) {
1682 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1683 checkGLcall("glGenFencesAPPLE");
1684 } else if(GL_SUPPORT(NV_FENCE)) {
1685 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1686 checkGLcall("glGenFencesNV");
1688 LEAVE_GL();
1689 break;
1691 case WINED3DQUERYTYPE_VCACHE:
1692 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1693 case WINED3DQUERYTYPE_VERTEXSTATS:
1694 case WINED3DQUERYTYPE_TIMESTAMP:
1695 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1696 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1697 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1698 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1699 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1700 case WINED3DQUERYTYPE_PIXELTIMINGS:
1701 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1702 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1703 default:
1704 object->extendedData = 0;
1705 FIXME("(%p) Unhandled query type %d\n",This , Type);
1707 TRACE("(%p) : Created Query %p\n", This, object);
1708 return WINED3D_OK;
1711 /*****************************************************************************
1712 * IWineD3DDeviceImpl_SetupFullscreenWindow
1714 * Helper function that modifies a HWND's Style and ExStyle for proper
1715 * fullscreen use.
1717 * Params:
1718 * iface: Pointer to the IWineD3DDevice interface
1719 * window: Window to setup
1721 *****************************************************************************/
1722 static LONG fullscreen_style(LONG orig_style) {
1723 LONG style = orig_style;
1724 style &= ~WS_CAPTION;
1725 style &= ~WS_THICKFRAME;
1727 /* Make sure the window is managed, otherwise we won't get keyboard input */
1728 style |= WS_POPUP | WS_SYSMENU;
1730 return style;
1733 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1734 LONG exStyle = orig_exStyle;
1736 /* Filter out window decorations */
1737 exStyle &= ~WS_EX_WINDOWEDGE;
1738 exStyle &= ~WS_EX_CLIENTEDGE;
1740 return exStyle;
1743 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1746 LONG style, exStyle;
1747 /* Don't do anything if an original style is stored.
1748 * That shouldn't happen
1750 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1751 if (This->style || This->exStyle) {
1752 ERR("(%p): Want to change the window parameters of HWND %p, but "
1753 "another style is stored for restoration afterwards\n", This, window);
1756 /* Get the parameters and save them */
1757 style = GetWindowLongW(window, GWL_STYLE);
1758 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1759 This->style = style;
1760 This->exStyle = exStyle;
1762 style = fullscreen_style(style);
1763 exStyle = fullscreen_exStyle(exStyle);
1765 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1766 This->style, This->exStyle, style, exStyle);
1768 SetWindowLongW(window, GWL_STYLE, style);
1769 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1771 /* Inform the window about the update. */
1772 SetWindowPos(window, HWND_TOP, 0, 0,
1773 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1776 /*****************************************************************************
1777 * IWineD3DDeviceImpl_RestoreWindow
1779 * Helper function that restores a windows' properties when taking it out
1780 * of fullscreen mode
1782 * Params:
1783 * iface: Pointer to the IWineD3DDevice interface
1784 * window: Window to setup
1786 *****************************************************************************/
1787 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1788 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1789 LONG style, exStyle;
1791 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1792 * switch, do nothing
1794 if (!This->style && !This->exStyle) return;
1796 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1797 This, window, This->style, This->exStyle);
1799 style = GetWindowLongW(window, GWL_STYLE);
1800 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1802 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1803 * Some applications change it before calling Reset() when switching between windowed and
1804 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1806 if(style == fullscreen_style(This->style) &&
1807 exStyle == fullscreen_style(This->exStyle)) {
1808 SetWindowLongW(window, GWL_STYLE, This->style);
1809 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1812 /* Delete the old values */
1813 This->style = 0;
1814 This->exStyle = 0;
1816 /* Inform the window about the update */
1817 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1818 0, 0, 0, 0, /* Pos, Size, ignored */
1819 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1822 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1823 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1824 WINED3DPRESENT_PARAMETERS *pPresentationParameters, IWineD3DSwapChain **ppSwapChain,
1825 IUnknown *parent, WINED3DSURFTYPE surface_type)
1827 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1829 HDC hDc;
1830 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1831 HRESULT hr;
1832 IUnknown *bufferParent;
1833 BOOL displaymode_set = FALSE;
1834 WINED3DDISPLAYMODE Mode;
1835 const struct GlPixelFormatDesc *format_desc;
1837 TRACE("(%p) : Created Additional Swap Chain\n", This);
1839 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1840 * does a device hold a reference to a swap chain giving them a lifetime of the device
1841 * or does the swap chain notify the device of its destruction.
1842 *******************************/
1844 /* Check the params */
1845 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1846 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1847 return WINED3DERR_INVALIDCALL;
1848 } else if (pPresentationParameters->BackBufferCount > 1) {
1849 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");
1852 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1853 if(!object)
1855 ERR("Out of memory\n");
1856 *ppSwapChain = NULL;
1857 return WINED3DERR_OUTOFVIDEOMEMORY;
1860 switch(surface_type) {
1861 case SURFACE_GDI:
1862 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1863 break;
1864 case SURFACE_OPENGL:
1865 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1866 break;
1867 case SURFACE_UNKNOWN:
1868 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1869 HeapFree(GetProcessHeap(), 0, object);
1870 return WINED3DERR_INVALIDCALL;
1872 object->wineD3DDevice = This;
1873 object->parent = parent;
1874 object->ref = 1;
1876 *ppSwapChain = (IWineD3DSwapChain *)object;
1878 /*********************
1879 * Lookup the window Handle and the relating X window handle
1880 ********************/
1882 /* Setup hwnd we are using, plus which display this equates to */
1883 object->win_handle = pPresentationParameters->hDeviceWindow;
1884 if (!object->win_handle) {
1885 object->win_handle = This->createParms.hFocusWindow;
1887 if(!pPresentationParameters->Windowed && object->win_handle) {
1888 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1889 pPresentationParameters->BackBufferWidth,
1890 pPresentationParameters->BackBufferHeight);
1893 hDc = GetDC(object->win_handle);
1894 TRACE("Using hDc %p\n", hDc);
1896 if (NULL == hDc) {
1897 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1898 return WINED3DERR_NOTAVAILABLE;
1901 /* Get info on the current display setup */
1902 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1903 object->orig_width = Mode.Width;
1904 object->orig_height = Mode.Height;
1905 object->orig_fmt = Mode.Format;
1906 format_desc = getFormatDescEntry(Mode.Format, &GLINFO_LOCATION);
1908 if (pPresentationParameters->Windowed &&
1909 ((pPresentationParameters->BackBufferWidth == 0) ||
1910 (pPresentationParameters->BackBufferHeight == 0) ||
1911 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1913 RECT Rect;
1914 GetClientRect(object->win_handle, &Rect);
1916 if (pPresentationParameters->BackBufferWidth == 0) {
1917 pPresentationParameters->BackBufferWidth = Rect.right;
1918 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1920 if (pPresentationParameters->BackBufferHeight == 0) {
1921 pPresentationParameters->BackBufferHeight = Rect.bottom;
1922 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1924 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1925 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1926 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1930 /* Put the correct figures in the presentation parameters */
1931 TRACE("Copying across presentation parameters\n");
1932 object->presentParms = *pPresentationParameters;
1934 TRACE("calling rendertarget CB\n");
1935 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1936 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1937 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1938 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->frontBuffer);
1939 if (SUCCEEDED(hr)) {
1940 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1941 ((IWineD3DSurfaceImpl *)object->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
1942 if(surface_type == SURFACE_OPENGL) {
1943 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1945 } else {
1946 ERR("Failed to create the front buffer\n");
1947 goto error;
1950 /*********************
1951 * Windowed / Fullscreen
1952 *******************/
1955 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1956 * so we should really check to see if there is a fullscreen swapchain already
1957 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1958 **************************************/
1960 if (!pPresentationParameters->Windowed) {
1961 WINED3DDISPLAYMODE mode;
1964 /* Change the display settings */
1965 mode.Width = pPresentationParameters->BackBufferWidth;
1966 mode.Height = pPresentationParameters->BackBufferHeight;
1967 mode.Format = pPresentationParameters->BackBufferFormat;
1968 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1970 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1971 displaymode_set = TRUE;
1975 * Create an opengl context for the display visual
1976 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1977 * use different properties after that point in time. FIXME: How to handle when requested format
1978 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1979 * it chooses is identical to the one already being used!
1980 **********************************/
1981 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1983 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1984 if(!object->context) {
1985 ERR("Failed to create the context array\n");
1986 hr = E_OUTOFMEMORY;
1987 goto error;
1989 object->num_contexts = 1;
1991 if(surface_type == SURFACE_OPENGL) {
1992 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1993 if (!object->context[0]) {
1994 ERR("Failed to create a new context\n");
1995 hr = WINED3DERR_NOTAVAILABLE;
1996 goto error;
1997 } else {
1998 TRACE("Context created (HWND=%p, glContext=%p)\n",
1999 object->win_handle, object->context[0]->glCtx);
2003 /*********************
2004 * Create the back, front and stencil buffers
2005 *******************/
2006 if(object->presentParms.BackBufferCount > 0) {
2007 UINT i;
2009 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
2010 if(!object->backBuffer) {
2011 ERR("Out of memory\n");
2012 hr = E_OUTOFMEMORY;
2013 goto error;
2016 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
2017 TRACE("calling rendertarget CB\n");
2018 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
2019 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
2020 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
2021 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->backBuffer[i]);
2022 if(SUCCEEDED(hr)) {
2023 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
2024 ((IWineD3DSurfaceImpl *)object->backBuffer[i])->Flags |= SFLAG_SWAPCHAIN;
2025 } else {
2026 ERR("Cannot create new back buffer\n");
2027 goto error;
2029 if(surface_type == SURFACE_OPENGL) {
2030 ENTER_GL();
2031 glDrawBuffer(GL_BACK);
2032 checkGLcall("glDrawBuffer(GL_BACK)");
2033 LEAVE_GL();
2036 } else {
2037 object->backBuffer = NULL;
2039 /* Single buffering - draw to front buffer */
2040 if(surface_type == SURFACE_OPENGL) {
2041 ENTER_GL();
2042 glDrawBuffer(GL_FRONT);
2043 checkGLcall("glDrawBuffer(GL_FRONT)");
2044 LEAVE_GL();
2048 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
2049 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
2050 TRACE("Creating depth stencil buffer\n");
2051 if (This->auto_depth_stencil_buffer == NULL ) {
2052 hr = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent, parent,
2053 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
2054 object->presentParms.AutoDepthStencilFormat, object->presentParms.MultiSampleType,
2055 object->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */,
2056 &This->auto_depth_stencil_buffer);
2057 if (SUCCEEDED(hr)) {
2058 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
2059 } else {
2060 ERR("Failed to create the auto depth stencil\n");
2061 goto error;
2066 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
2068 TRACE("Created swapchain %p\n", object);
2069 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
2070 return WINED3D_OK;
2072 error:
2073 if (displaymode_set) {
2074 DEVMODEW devmode;
2075 RECT clip_rc;
2077 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
2078 ClipCursor(NULL);
2080 /* Change the display settings */
2081 memset(&devmode, 0, sizeof(devmode));
2082 devmode.dmSize = sizeof(devmode);
2083 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2084 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2085 devmode.dmPelsWidth = object->orig_width;
2086 devmode.dmPelsHeight = object->orig_height;
2087 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
2090 if (object->backBuffer) {
2091 UINT i;
2092 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
2093 if(object->backBuffer[i]) {
2094 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
2095 IUnknown_Release(bufferParent); /* once for the get parent */
2096 if (IUnknown_Release(bufferParent) > 0) {
2097 FIXME("(%p) Something's still holding the back buffer\n",This);
2101 HeapFree(GetProcessHeap(), 0, object->backBuffer);
2102 object->backBuffer = NULL;
2104 if(object->context && object->context[0])
2105 DestroyContext(This, object->context[0]);
2106 if(object->frontBuffer) {
2107 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
2108 IUnknown_Release(bufferParent); /* once for the get parent */
2109 if (IUnknown_Release(bufferParent) > 0) {
2110 FIXME("(%p) Something's still holding the front buffer\n",This);
2113 HeapFree(GetProcessHeap(), 0, object);
2114 return hr;
2117 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
2118 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
2119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2120 TRACE("(%p)\n", This);
2122 return This->NumberOfSwapChains;
2125 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
2126 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2127 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
2129 if(iSwapChain < This->NumberOfSwapChains) {
2130 *pSwapChain = This->swapchains[iSwapChain];
2131 IWineD3DSwapChain_AddRef(*pSwapChain);
2132 TRACE("(%p) returning %p\n", This, *pSwapChain);
2133 return WINED3D_OK;
2134 } else {
2135 TRACE("Swapchain out of range\n");
2136 *pSwapChain = NULL;
2137 return WINED3DERR_INVALIDCALL;
2141 /*****
2142 * Vertex Declaration
2143 *****/
2144 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
2145 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
2146 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2147 IWineD3DVertexDeclarationImpl *object = NULL;
2148 HRESULT hr = WINED3D_OK;
2150 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
2151 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
2153 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2154 if(!object)
2156 ERR("Out of memory\n");
2157 *ppVertexDeclaration = NULL;
2158 return WINED3DERR_OUTOFVIDEOMEMORY;
2161 object->lpVtbl = &IWineD3DVertexDeclaration_Vtbl;
2162 object->wineD3DDevice = This;
2163 object->parent = parent;
2164 object->ref = 1;
2166 *ppVertexDeclaration = (IWineD3DVertexDeclaration *)object;
2168 hr = vertexdeclaration_init(object, elements, element_count);
2170 if(FAILED(hr)) {
2171 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
2172 *ppVertexDeclaration = NULL;
2175 return hr;
2178 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
2179 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
2181 unsigned int idx, idx2;
2182 unsigned int offset;
2183 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
2184 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
2185 BOOL has_blend_idx = has_blend &&
2186 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
2187 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
2188 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
2189 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
2190 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
2191 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
2192 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
2194 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
2195 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
2196 WINED3DVERTEXELEMENT *elements = NULL;
2198 unsigned int size;
2199 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
2200 if (has_blend_idx) num_blends--;
2202 /* Compute declaration size */
2203 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
2204 has_psize + has_diffuse + has_specular + num_textures;
2206 /* convert the declaration */
2207 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
2208 if (!elements) return ~0U;
2210 idx = 0;
2211 if (has_pos) {
2212 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
2213 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
2214 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
2216 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
2217 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
2218 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
2220 else {
2221 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
2222 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
2224 elements[idx].usage_idx = 0;
2225 idx++;
2227 if (has_blend && (num_blends > 0)) {
2228 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
2229 elements[idx].format = WINED3DFMT_A8R8G8B8;
2230 else {
2231 switch(num_blends) {
2232 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
2233 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
2234 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
2235 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
2236 default:
2237 ERR("Unexpected amount of blend values: %u\n", num_blends);
2240 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
2241 elements[idx].usage_idx = 0;
2242 idx++;
2244 if (has_blend_idx) {
2245 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
2246 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
2247 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
2248 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
2249 elements[idx].format = WINED3DFMT_A8R8G8B8;
2250 else
2251 elements[idx].format = WINED3DFMT_R32_FLOAT;
2252 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
2253 elements[idx].usage_idx = 0;
2254 idx++;
2256 if (has_normal) {
2257 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
2258 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
2259 elements[idx].usage_idx = 0;
2260 idx++;
2262 if (has_psize) {
2263 elements[idx].format = WINED3DFMT_R32_FLOAT;
2264 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
2265 elements[idx].usage_idx = 0;
2266 idx++;
2268 if (has_diffuse) {
2269 elements[idx].format = WINED3DFMT_A8R8G8B8;
2270 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
2271 elements[idx].usage_idx = 0;
2272 idx++;
2274 if (has_specular) {
2275 elements[idx].format = WINED3DFMT_A8R8G8B8;
2276 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
2277 elements[idx].usage_idx = 1;
2278 idx++;
2280 for (idx2 = 0; idx2 < num_textures; idx2++) {
2281 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
2282 switch (numcoords) {
2283 case WINED3DFVF_TEXTUREFORMAT1:
2284 elements[idx].format = WINED3DFMT_R32_FLOAT;
2285 break;
2286 case WINED3DFVF_TEXTUREFORMAT2:
2287 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
2288 break;
2289 case WINED3DFVF_TEXTUREFORMAT3:
2290 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
2291 break;
2292 case WINED3DFVF_TEXTUREFORMAT4:
2293 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
2294 break;
2296 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
2297 elements[idx].usage_idx = idx2;
2298 idx++;
2301 /* Now compute offsets, and initialize the rest of the fields */
2302 for (idx = 0, offset = 0; idx < size; ++idx)
2304 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
2305 elements[idx].input_slot = 0;
2306 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
2307 elements[idx].offset = offset;
2308 offset += format_desc->component_count * format_desc->component_size;
2311 *ppVertexElements = elements;
2312 return size;
2315 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
2316 WINED3DVERTEXELEMENT* elements = NULL;
2317 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2318 unsigned int size;
2319 DWORD hr;
2321 size = ConvertFvfToDeclaration(This, Fvf, &elements);
2322 if (size == ~0U) return WINED3DERR_OUTOFVIDEOMEMORY;
2324 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
2325 HeapFree(GetProcessHeap(), 0, elements);
2326 if (hr != S_OK) return hr;
2328 return WINED3D_OK;
2331 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
2332 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2333 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
2334 HRESULT hr = WINED3D_OK;
2336 if (!pFunction) return WINED3DERR_INVALIDCALL;
2338 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2339 if (!object)
2341 ERR("Out of memory\n");
2342 *ppVertexShader = NULL;
2343 return WINED3DERR_OUTOFVIDEOMEMORY;
2346 object->lpVtbl = &IWineD3DVertexShader_Vtbl;
2347 object->parent = parent;
2348 shader_init(&object->baseShader, iface);
2349 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2350 *ppVertexShader = (IWineD3DVertexShader *)object;
2352 TRACE("(%p) : Created vertex shader %p\n", This, *ppVertexShader);
2354 if (vertex_declaration) {
2355 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
2358 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction, NULL);
2359 if (FAILED(hr))
2361 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2362 IWineD3DVertexShader_Release(*ppVertexShader);
2363 *ppVertexShader = NULL;
2364 return hr;
2367 return hr;
2370 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
2371 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
2372 IWineD3DPixelShader **ppPixelShader, IUnknown *parent)
2374 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2375 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
2376 HRESULT hr = WINED3D_OK;
2378 if (!pFunction) return WINED3DERR_INVALIDCALL;
2380 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2381 if (!object)
2383 ERR("Out of memory\n");
2384 *ppPixelShader = NULL;
2385 return WINED3DERR_OUTOFVIDEOMEMORY;
2388 object->lpVtbl = &IWineD3DPixelShader_Vtbl;
2389 object->parent = parent;
2390 shader_init(&object->baseShader, iface);
2391 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2392 *ppPixelShader = (IWineD3DPixelShader *)object;
2394 TRACE("(%p) : Created pixel shader %p\n", This, *ppPixelShader);
2396 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction, output_signature);
2397 if (FAILED(hr))
2399 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2400 IWineD3DPixelShader_Release(*ppPixelShader);
2401 *ppPixelShader = NULL;
2402 return hr;
2405 return hr;
2408 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
2409 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
2411 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2412 IWineD3DPaletteImpl *object;
2413 HRESULT hr;
2414 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
2416 /* Create the new object */
2417 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
2418 if(!object) {
2419 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
2420 return E_OUTOFMEMORY;
2423 object->lpVtbl = &IWineD3DPalette_Vtbl;
2424 object->ref = 1;
2425 object->Flags = Flags;
2426 object->parent = Parent;
2427 object->wineD3DDevice = This;
2428 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2429 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2431 if(!object->hpal) {
2432 HeapFree( GetProcessHeap(), 0, object);
2433 return E_OUTOFMEMORY;
2436 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2437 if(FAILED(hr)) {
2438 IWineD3DPalette_Release((IWineD3DPalette *) object);
2439 return hr;
2442 *Palette = (IWineD3DPalette *) object;
2444 return WINED3D_OK;
2447 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
2448 HBITMAP hbm;
2449 BITMAP bm;
2450 HRESULT hr;
2451 HDC dcb = NULL, dcs = NULL;
2452 WINEDDCOLORKEY colorkey;
2454 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
2455 if(hbm)
2457 GetObjectA(hbm, sizeof(BITMAP), &bm);
2458 dcb = CreateCompatibleDC(NULL);
2459 if(!dcb) goto out;
2460 SelectObject(dcb, hbm);
2462 else
2464 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
2465 * couldn't be loaded
2467 memset(&bm, 0, sizeof(bm));
2468 bm.bmWidth = 32;
2469 bm.bmHeight = 32;
2472 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
2473 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
2474 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL, NULL);
2475 if(FAILED(hr)) {
2476 ERR("Wine logo requested, but failed to create surface\n");
2477 goto out;
2480 if(dcb) {
2481 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
2482 if(FAILED(hr)) goto out;
2483 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
2484 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
2486 colorkey.dwColorSpaceLowValue = 0;
2487 colorkey.dwColorSpaceHighValue = 0;
2488 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2489 } else {
2490 /* Fill the surface with a white color to show that wined3d is there */
2491 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2494 out:
2495 if(dcb) {
2496 DeleteDC(dcb);
2498 if(hbm) {
2499 DeleteObject(hbm);
2501 return;
2504 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2505 unsigned int i;
2506 /* Under DirectX you can have texture stage operations even if no texture is
2507 bound, whereas opengl will only do texture operations when a valid texture is
2508 bound. We emulate this by creating dummy textures and binding them to each
2509 texture stage, but disable all stages by default. Hence if a stage is enabled
2510 then the default texture will kick in until replaced by a SetTexture call */
2511 ENTER_GL();
2513 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2514 /* The dummy texture does not have client storage backing */
2515 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2516 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2518 for (i = 0; i < GL_LIMITS(textures); i++) {
2519 GLubyte white = 255;
2521 /* Make appropriate texture active */
2522 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2523 checkGLcall("glActiveTextureARB");
2525 /* Generate an opengl texture name */
2526 glGenTextures(1, &This->dummyTextureName[i]);
2527 checkGLcall("glGenTextures");
2528 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2530 /* Generate a dummy 2d texture (not using 1d because they cause many
2531 * DRI drivers fall back to sw) */
2532 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2533 checkGLcall("glBindTexture");
2535 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2536 checkGLcall("glTexImage2D");
2538 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2539 /* Reenable because if supported it is enabled by default */
2540 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2541 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2544 LEAVE_GL();
2547 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
2548 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2550 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2551 IWineD3DSwapChainImpl *swapchain = NULL;
2552 HRESULT hr;
2553 DWORD state;
2554 unsigned int i;
2556 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
2558 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2559 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2561 /* TODO: Test if OpenGL is compiled in and loaded */
2563 TRACE("(%p) : Creating stateblock\n", This);
2564 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2565 hr = IWineD3DDevice_CreateStateBlock(iface,
2566 WINED3DSBT_INIT,
2567 (IWineD3DStateBlock **)&This->stateBlock,
2568 NULL);
2569 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2570 WARN("Failed to create stateblock\n");
2571 goto err_out;
2573 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2574 This->updateStateBlock = This->stateBlock;
2575 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2577 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2578 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2580 This->NumberOfPalettes = 1;
2581 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2582 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2583 ERR("Out of memory!\n");
2584 goto err_out;
2586 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2587 if(!This->palettes[0]) {
2588 ERR("Out of memory!\n");
2589 goto err_out;
2591 for (i = 0; i < 256; ++i) {
2592 This->palettes[0][i].peRed = 0xFF;
2593 This->palettes[0][i].peGreen = 0xFF;
2594 This->palettes[0][i].peBlue = 0xFF;
2595 This->palettes[0][i].peFlags = 0xFF;
2597 This->currentPalette = 0;
2599 /* Initialize the texture unit mapping to a 1:1 mapping */
2600 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2601 if (state < GL_LIMITS(fragment_samplers)) {
2602 This->texUnitMap[state] = state;
2603 This->rev_tex_unit_map[state] = state;
2604 } else {
2605 This->texUnitMap[state] = -1;
2606 This->rev_tex_unit_map[state] = -1;
2610 /* Setup the implicit swapchain */
2611 TRACE("Creating implicit swapchain\n");
2612 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2613 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2614 if (FAILED(hr))
2616 WARN("Failed to create implicit swapchain\n");
2617 goto err_out;
2620 This->NumberOfSwapChains = 1;
2621 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2622 if(!This->swapchains) {
2623 ERR("Out of memory!\n");
2624 goto err_out;
2626 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2628 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2629 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2630 This->render_targets[0] = swapchain->backBuffer[0];
2631 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2633 else {
2634 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2635 This->render_targets[0] = swapchain->frontBuffer;
2636 This->lastActiveRenderTarget = swapchain->frontBuffer;
2638 IWineD3DSurface_AddRef(This->render_targets[0]);
2639 This->activeContext = swapchain->context[0];
2640 This->lastThread = GetCurrentThreadId();
2642 /* Depth Stencil support */
2643 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2644 if (NULL != This->stencilBufferTarget) {
2645 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2648 hr = This->shader_backend->shader_alloc_private(iface);
2649 if(FAILED(hr)) {
2650 TRACE("Shader private data couldn't be allocated\n");
2651 goto err_out;
2653 hr = This->frag_pipe->alloc_private(iface);
2654 if(FAILED(hr)) {
2655 TRACE("Fragment pipeline private data couldn't be allocated\n");
2656 goto err_out;
2658 hr = This->blitter->alloc_private(iface);
2659 if(FAILED(hr)) {
2660 TRACE("Blitter private data couldn't be allocated\n");
2661 goto err_out;
2664 /* Set up some starting GL setup */
2666 /* Setup all the devices defaults */
2667 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2668 create_dummy_textures(This);
2670 ENTER_GL();
2672 /* Initialize the current view state */
2673 This->view_ident = 1;
2674 This->contexts[0]->last_was_rhw = 0;
2675 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2676 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2678 switch(wined3d_settings.offscreen_rendering_mode) {
2679 case ORM_FBO:
2680 case ORM_PBUFFER:
2681 This->offscreenBuffer = GL_BACK;
2682 break;
2684 case ORM_BACKBUFFER:
2686 if(This->activeContext->aux_buffers > 0) {
2687 TRACE("Using auxilliary buffer for offscreen rendering\n");
2688 This->offscreenBuffer = GL_AUX0;
2689 } else {
2690 TRACE("Using back buffer for offscreen rendering\n");
2691 This->offscreenBuffer = GL_BACK;
2696 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2697 LEAVE_GL();
2699 /* Clear the screen */
2700 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2701 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2702 0x00, 1.0, 0);
2704 This->d3d_initialized = TRUE;
2706 if(wined3d_settings.logo) {
2707 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2709 This->highest_dirty_ps_const = 0;
2710 This->highest_dirty_vs_const = 0;
2711 return WINED3D_OK;
2713 err_out:
2714 HeapFree(GetProcessHeap(), 0, This->render_targets);
2715 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2716 HeapFree(GetProcessHeap(), 0, This->swapchains);
2717 This->NumberOfSwapChains = 0;
2718 if(This->palettes) {
2719 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2720 HeapFree(GetProcessHeap(), 0, This->palettes);
2722 This->NumberOfPalettes = 0;
2723 if(swapchain) {
2724 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2726 if(This->stateBlock) {
2727 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2728 This->stateBlock = NULL;
2730 if (This->blit_priv) {
2731 This->blitter->free_private(iface);
2733 if (This->fragment_priv) {
2734 This->frag_pipe->free_private(iface);
2736 if (This->shader_priv) {
2737 This->shader_backend->shader_free_private(iface);
2739 return hr;
2742 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2743 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2745 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2746 IWineD3DSwapChainImpl *swapchain = NULL;
2747 HRESULT hr;
2749 /* Setup the implicit swapchain */
2750 TRACE("Creating implicit swapchain\n");
2751 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2752 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2753 if (FAILED(hr))
2755 WARN("Failed to create implicit swapchain\n");
2756 goto err_out;
2759 This->NumberOfSwapChains = 1;
2760 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2761 if(!This->swapchains) {
2762 ERR("Out of memory!\n");
2763 goto err_out;
2765 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2766 return WINED3D_OK;
2768 err_out:
2769 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2770 return hr;
2773 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2775 IWineD3DResource_UnLoad(resource);
2776 IWineD3DResource_Release(resource);
2777 return WINED3D_OK;
2780 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2781 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2782 int sampler;
2783 UINT i;
2784 TRACE("(%p)\n", This);
2786 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2788 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2789 * it was created. Thus make sure a context is active for the glDelete* calls
2791 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2793 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2795 /* Unload resources */
2796 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2798 TRACE("Deleting high order patches\n");
2799 for(i = 0; i < PATCHMAP_SIZE; i++) {
2800 struct list *e1, *e2;
2801 struct WineD3DRectPatch *patch;
2802 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2803 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2804 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2808 /* Delete the palette conversion shader if it is around */
2809 if(This->paletteConversionShader) {
2810 ENTER_GL();
2811 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2812 LEAVE_GL();
2813 This->paletteConversionShader = 0;
2816 /* Delete the pbuffer context if there is any */
2817 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2819 /* Delete the mouse cursor texture */
2820 if(This->cursorTexture) {
2821 ENTER_GL();
2822 glDeleteTextures(1, &This->cursorTexture);
2823 LEAVE_GL();
2824 This->cursorTexture = 0;
2827 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2828 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2830 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2831 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2834 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2835 * private data, it might contain opengl pointers
2837 if(This->depth_blt_texture) {
2838 ENTER_GL();
2839 glDeleteTextures(1, &This->depth_blt_texture);
2840 LEAVE_GL();
2841 This->depth_blt_texture = 0;
2843 if (This->depth_blt_rb) {
2844 ENTER_GL();
2845 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2846 LEAVE_GL();
2847 This->depth_blt_rb = 0;
2848 This->depth_blt_rb_w = 0;
2849 This->depth_blt_rb_h = 0;
2852 /* Release the update stateblock */
2853 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2854 if(This->updateStateBlock != This->stateBlock)
2855 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2857 This->updateStateBlock = NULL;
2859 { /* because were not doing proper internal refcounts releasing the primary state block
2860 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2861 to set this->stateBlock = NULL; first */
2862 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2863 This->stateBlock = NULL;
2865 /* Release the stateblock */
2866 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2867 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2871 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2872 This->blitter->free_private(iface);
2873 This->frag_pipe->free_private(iface);
2874 This->shader_backend->shader_free_private(iface);
2876 /* Release the buffers (with sanity checks)*/
2877 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2878 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2879 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2880 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2882 This->stencilBufferTarget = NULL;
2884 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2885 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2886 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2888 TRACE("Setting rendertarget to NULL\n");
2889 This->render_targets[0] = NULL;
2891 if (This->auto_depth_stencil_buffer) {
2892 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2893 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2895 This->auto_depth_stencil_buffer = NULL;
2898 for(i=0; i < This->NumberOfSwapChains; i++) {
2899 TRACE("Releasing the implicit swapchain %d\n", i);
2900 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2901 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2905 HeapFree(GetProcessHeap(), 0, This->swapchains);
2906 This->swapchains = NULL;
2907 This->NumberOfSwapChains = 0;
2909 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2910 HeapFree(GetProcessHeap(), 0, This->palettes);
2911 This->palettes = NULL;
2912 This->NumberOfPalettes = 0;
2914 HeapFree(GetProcessHeap(), 0, This->render_targets);
2915 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2916 This->render_targets = NULL;
2917 This->draw_buffers = NULL;
2919 This->d3d_initialized = FALSE;
2920 return WINED3D_OK;
2923 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2924 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2925 unsigned int i;
2927 for(i=0; i < This->NumberOfSwapChains; i++) {
2928 TRACE("Releasing the implicit swapchain %d\n", i);
2929 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2930 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2934 HeapFree(GetProcessHeap(), 0, This->swapchains);
2935 This->swapchains = NULL;
2936 This->NumberOfSwapChains = 0;
2937 return WINED3D_OK;
2940 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2941 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2942 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2944 * There is no way to deactivate thread safety once it is enabled.
2946 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2947 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2949 /*For now just store the flag(needed in case of ddraw) */
2950 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2952 return;
2955 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2956 const WINED3DDISPLAYMODE* pMode) {
2957 DEVMODEW devmode;
2958 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2959 LONG ret;
2960 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &GLINFO_LOCATION);
2961 RECT clip_rc;
2963 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2965 /* Resize the screen even without a window:
2966 * The app could have unset it with SetCooperativeLevel, but not called
2967 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2968 * but we don't have any hwnd
2971 memset(&devmode, 0, sizeof(devmode));
2972 devmode.dmSize = sizeof(devmode);
2973 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2974 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2975 devmode.dmPelsWidth = pMode->Width;
2976 devmode.dmPelsHeight = pMode->Height;
2978 devmode.dmDisplayFrequency = pMode->RefreshRate;
2979 if (pMode->RefreshRate != 0) {
2980 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2983 /* Only change the mode if necessary */
2984 if( (This->ddraw_width == pMode->Width) &&
2985 (This->ddraw_height == pMode->Height) &&
2986 (This->ddraw_format == pMode->Format) &&
2987 (pMode->RefreshRate == 0) ) {
2988 return WINED3D_OK;
2991 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2992 if (ret != DISP_CHANGE_SUCCESSFUL) {
2993 if(devmode.dmDisplayFrequency != 0) {
2994 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2995 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2996 devmode.dmDisplayFrequency = 0;
2997 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2999 if(ret != DISP_CHANGE_SUCCESSFUL) {
3000 return WINED3DERR_NOTAVAILABLE;
3004 /* Store the new values */
3005 This->ddraw_width = pMode->Width;
3006 This->ddraw_height = pMode->Height;
3007 This->ddraw_format = pMode->Format;
3009 /* And finally clip mouse to our screen */
3010 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
3011 ClipCursor(&clip_rc);
3013 return WINED3D_OK;
3016 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
3017 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3018 *ppD3D= This->wineD3D;
3019 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
3020 IWineD3D_AddRef(*ppD3D);
3021 return WINED3D_OK;
3024 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
3025 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3027 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
3028 (This->adapter->TextureRam/(1024*1024)),
3029 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
3030 /* return simulated texture memory left */
3031 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
3034 /*****
3035 * Get / Set Stream Source
3036 *****/
3037 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
3038 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
3040 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3041 IWineD3DBuffer *oldSrc;
3043 if (StreamNumber >= MAX_STREAMS) {
3044 WARN("Stream out of range %d\n", StreamNumber);
3045 return WINED3DERR_INVALIDCALL;
3046 } else if(OffsetInBytes & 0x3) {
3047 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
3048 return WINED3DERR_INVALIDCALL;
3051 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
3052 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
3054 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
3056 if(oldSrc == pStreamData &&
3057 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
3058 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
3059 TRACE("Application is setting the old values over, nothing to do\n");
3060 return WINED3D_OK;
3063 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
3064 if (pStreamData) {
3065 This->updateStateBlock->streamStride[StreamNumber] = Stride;
3066 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
3069 /* Handle recording of state blocks */
3070 if (This->isRecordingState) {
3071 TRACE("Recording... not performing anything\n");
3072 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
3073 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
3074 return WINED3D_OK;
3077 if (pStreamData != NULL) {
3078 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
3079 IWineD3DBuffer_AddRef(pStreamData);
3081 if (oldSrc != NULL) {
3082 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
3083 IWineD3DBuffer_Release(oldSrc);
3086 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3088 return WINED3D_OK;
3091 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
3092 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
3094 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3096 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
3097 This->stateBlock->streamSource[StreamNumber],
3098 This->stateBlock->streamOffset[StreamNumber],
3099 This->stateBlock->streamStride[StreamNumber]);
3101 if (StreamNumber >= MAX_STREAMS) {
3102 WARN("Stream out of range %d\n", StreamNumber);
3103 return WINED3DERR_INVALIDCALL;
3105 *pStream = This->stateBlock->streamSource[StreamNumber];
3106 *pStride = This->stateBlock->streamStride[StreamNumber];
3107 if (pOffset) {
3108 *pOffset = This->stateBlock->streamOffset[StreamNumber];
3111 if (*pStream != NULL) {
3112 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
3114 return WINED3D_OK;
3117 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
3118 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3119 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
3120 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
3122 /* Verify input at least in d3d9 this is invalid*/
3123 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
3124 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
3125 return WINED3DERR_INVALIDCALL;
3127 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
3128 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
3129 return WINED3DERR_INVALIDCALL;
3131 if( Divider == 0 ){
3132 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
3133 return WINED3DERR_INVALIDCALL;
3136 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
3137 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
3139 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
3140 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
3142 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
3143 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
3144 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3147 return WINED3D_OK;
3150 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
3151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3153 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
3154 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
3156 TRACE("(%p) : returning %d\n", This, *Divider);
3158 return WINED3D_OK;
3161 /*****
3162 * Get / Set & Multiply Transform
3163 *****/
3164 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
3165 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3167 /* Most of this routine, comments included copied from ddraw tree initially: */
3168 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
3170 /* Handle recording of state blocks */
3171 if (This->isRecordingState) {
3172 TRACE("Recording... not performing anything\n");
3173 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
3174 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
3175 return WINED3D_OK;
3179 * If the new matrix is the same as the current one,
3180 * we cut off any further processing. this seems to be a reasonable
3181 * optimization because as was noticed, some apps (warcraft3 for example)
3182 * tend towards setting the same matrix repeatedly for some reason.
3184 * From here on we assume that the new matrix is different, wherever it matters.
3186 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
3187 TRACE("The app is setting the same matrix over again\n");
3188 return WINED3D_OK;
3189 } else {
3190 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
3194 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
3195 where ViewMat = Camera space, WorldMat = world space.
3197 In OpenGL, camera and world space is combined into GL_MODELVIEW
3198 matrix. The Projection matrix stay projection matrix.
3201 /* Capture the times we can just ignore the change for now */
3202 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
3203 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
3204 /* Handled by the state manager */
3207 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
3208 return WINED3D_OK;
3211 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
3212 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3213 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
3214 *pMatrix = This->stateBlock->transforms[State];
3215 return WINED3D_OK;
3218 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
3219 const WINED3DMATRIX *mat = NULL;
3220 WINED3DMATRIX temp;
3222 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
3223 * below means it will be recorded in a state block change, but it
3224 * works regardless where it is recorded.
3225 * If this is found to be wrong, change to StateBlock.
3227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3228 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
3230 if (State <= HIGHEST_TRANSFORMSTATE)
3232 mat = &This->updateStateBlock->transforms[State];
3233 } else {
3234 FIXME("Unhandled transform state!!\n");
3237 multiply_matrix(&temp, mat, pMatrix);
3239 /* Apply change via set transform - will reapply to eg. lights this way */
3240 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
3243 /*****
3244 * Get / Set Light
3245 *****/
3246 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
3247 you can reference any indexes you want as long as that number max are enabled at any
3248 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
3249 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
3250 but when recording, just build a chain pretty much of commands to be replayed. */
3252 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
3253 float rho;
3254 PLIGHTINFOEL *object = NULL;
3255 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3256 struct list *e;
3258 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3259 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
3261 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
3262 * the gl driver.
3264 if(!pLight) {
3265 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
3266 return WINED3DERR_INVALIDCALL;
3269 switch(pLight->Type) {
3270 case WINED3DLIGHT_POINT:
3271 case WINED3DLIGHT_SPOT:
3272 case WINED3DLIGHT_PARALLELPOINT:
3273 case WINED3DLIGHT_GLSPOT:
3274 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
3275 * most wanted
3277 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
3278 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
3279 return WINED3DERR_INVALIDCALL;
3281 break;
3283 case WINED3DLIGHT_DIRECTIONAL:
3284 /* Ignores attenuation */
3285 break;
3287 default:
3288 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
3289 return WINED3DERR_INVALIDCALL;
3292 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3293 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3294 if(object->OriginalIndex == Index) break;
3295 object = NULL;
3298 if(!object) {
3299 TRACE("Adding new light\n");
3300 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
3301 if(!object) {
3302 ERR("Out of memory error when allocating a light\n");
3303 return E_OUTOFMEMORY;
3305 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
3306 object->glIndex = -1;
3307 object->OriginalIndex = Index;
3308 object->changed = TRUE;
3311 /* Initialize the object */
3312 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,
3313 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
3314 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
3315 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
3316 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
3317 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
3318 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
3320 /* Save away the information */
3321 object->OriginalParms = *pLight;
3323 switch (pLight->Type) {
3324 case WINED3DLIGHT_POINT:
3325 /* Position */
3326 object->lightPosn[0] = pLight->Position.x;
3327 object->lightPosn[1] = pLight->Position.y;
3328 object->lightPosn[2] = pLight->Position.z;
3329 object->lightPosn[3] = 1.0f;
3330 object->cutoff = 180.0f;
3331 /* FIXME: Range */
3332 break;
3334 case WINED3DLIGHT_DIRECTIONAL:
3335 /* Direction */
3336 object->lightPosn[0] = -pLight->Direction.x;
3337 object->lightPosn[1] = -pLight->Direction.y;
3338 object->lightPosn[2] = -pLight->Direction.z;
3339 object->lightPosn[3] = 0.0;
3340 object->exponent = 0.0f;
3341 object->cutoff = 180.0f;
3342 break;
3344 case WINED3DLIGHT_SPOT:
3345 /* Position */
3346 object->lightPosn[0] = pLight->Position.x;
3347 object->lightPosn[1] = pLight->Position.y;
3348 object->lightPosn[2] = pLight->Position.z;
3349 object->lightPosn[3] = 1.0;
3351 /* Direction */
3352 object->lightDirn[0] = pLight->Direction.x;
3353 object->lightDirn[1] = pLight->Direction.y;
3354 object->lightDirn[2] = pLight->Direction.z;
3355 object->lightDirn[3] = 1.0;
3358 * opengl-ish and d3d-ish spot lights use too different models for the
3359 * light "intensity" as a function of the angle towards the main light direction,
3360 * so we only can approximate very roughly.
3361 * however spot lights are rather rarely used in games (if ever used at all).
3362 * furthermore if still used, probably nobody pays attention to such details.
3364 if (pLight->Falloff == 0) {
3365 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
3366 * falloff resp. exponent parameter as an exponent, so the spot light lighting
3367 * will always be 1.0 for both of them, and we don't have to care for the
3368 * rest of the rather complex calculation
3370 object->exponent = 0;
3371 } else {
3372 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
3373 if (rho < 0.0001) rho = 0.0001f;
3374 object->exponent = -0.3/log(cos(rho/2));
3376 if (object->exponent > 128.0) {
3377 object->exponent = 128.0;
3379 object->cutoff = pLight->Phi*90/M_PI;
3381 /* FIXME: Range */
3382 break;
3384 default:
3385 FIXME("Unrecognized light type %d\n", pLight->Type);
3388 /* Update the live definitions if the light is currently assigned a glIndex */
3389 if (object->glIndex != -1 && !This->isRecordingState) {
3390 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
3392 return WINED3D_OK;
3395 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
3396 PLIGHTINFOEL *lightInfo = NULL;
3397 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3398 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
3399 struct list *e;
3400 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
3402 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3403 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3404 if(lightInfo->OriginalIndex == Index) break;
3405 lightInfo = NULL;
3408 if (lightInfo == NULL) {
3409 TRACE("Light information requested but light not defined\n");
3410 return WINED3DERR_INVALIDCALL;
3413 *pLight = lightInfo->OriginalParms;
3414 return WINED3D_OK;
3417 /*****
3418 * Get / Set Light Enable
3419 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
3420 *****/
3421 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
3422 PLIGHTINFOEL *lightInfo = NULL;
3423 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3424 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3425 struct list *e;
3426 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
3428 /* Tests show true = 128...not clear why */
3429 Enable = Enable? 128: 0;
3431 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3432 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3433 if(lightInfo->OriginalIndex == Index) break;
3434 lightInfo = NULL;
3436 TRACE("Found light: %p\n", lightInfo);
3438 /* Special case - enabling an undefined light creates one with a strict set of parms! */
3439 if (lightInfo == NULL) {
3441 TRACE("Light enabled requested but light not defined, so defining one!\n");
3442 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
3444 /* Search for it again! Should be fairly quick as near head of list */
3445 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3446 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3447 if(lightInfo->OriginalIndex == Index) break;
3448 lightInfo = NULL;
3450 if (lightInfo == NULL) {
3451 FIXME("Adding default lights has failed dismally\n");
3452 return WINED3DERR_INVALIDCALL;
3456 lightInfo->enabledChanged = TRUE;
3457 if(!Enable) {
3458 if(lightInfo->glIndex != -1) {
3459 if(!This->isRecordingState) {
3460 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
3463 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
3464 lightInfo->glIndex = -1;
3465 } else {
3466 TRACE("Light already disabled, nothing to do\n");
3468 lightInfo->enabled = FALSE;
3469 } else {
3470 lightInfo->enabled = TRUE;
3471 if (lightInfo->glIndex != -1) {
3472 /* nop */
3473 TRACE("Nothing to do as light was enabled\n");
3474 } else {
3475 int i;
3476 /* Find a free gl light */
3477 for(i = 0; i < This->maxConcurrentLights; i++) {
3478 if(This->updateStateBlock->activeLights[i] == NULL) {
3479 This->updateStateBlock->activeLights[i] = lightInfo;
3480 lightInfo->glIndex = i;
3481 break;
3484 if(lightInfo->glIndex == -1) {
3485 /* Our tests show that Windows returns D3D_OK in this situation, even with
3486 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3487 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3488 * as well for those lights.
3490 * TODO: Test how this affects rendering
3492 WARN("Too many concurrently active lights\n");
3493 return WINED3D_OK;
3496 /* i == lightInfo->glIndex */
3497 if(!This->isRecordingState) {
3498 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3503 return WINED3D_OK;
3506 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3508 PLIGHTINFOEL *lightInfo = NULL;
3509 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3510 struct list *e;
3511 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3512 TRACE("(%p) : for idx(%d)\n", This, Index);
3514 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3515 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3516 if(lightInfo->OriginalIndex == Index) break;
3517 lightInfo = NULL;
3520 if (lightInfo == NULL) {
3521 TRACE("Light enabled state requested but light not defined\n");
3522 return WINED3DERR_INVALIDCALL;
3524 /* true is 128 according to SetLightEnable */
3525 *pEnable = lightInfo->enabled ? 128 : 0;
3526 return WINED3D_OK;
3529 /*****
3530 * Get / Set Clip Planes
3531 *****/
3532 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3533 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3534 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3536 /* Validate Index */
3537 if (Index >= GL_LIMITS(clipplanes)) {
3538 TRACE("Application has requested clipplane this device doesn't support\n");
3539 return WINED3DERR_INVALIDCALL;
3542 This->updateStateBlock->changed.clipplane |= 1 << Index;
3544 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3545 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3546 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3547 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3548 TRACE("Application is setting old values over, nothing to do\n");
3549 return WINED3D_OK;
3552 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3553 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3554 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3555 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3557 /* Handle recording of state blocks */
3558 if (This->isRecordingState) {
3559 TRACE("Recording... not performing anything\n");
3560 return WINED3D_OK;
3563 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3565 return WINED3D_OK;
3568 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3569 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3570 TRACE("(%p) : for idx %d\n", This, Index);
3572 /* Validate Index */
3573 if (Index >= GL_LIMITS(clipplanes)) {
3574 TRACE("Application has requested clipplane this device doesn't support\n");
3575 return WINED3DERR_INVALIDCALL;
3578 pPlane[0] = This->stateBlock->clipplane[Index][0];
3579 pPlane[1] = This->stateBlock->clipplane[Index][1];
3580 pPlane[2] = This->stateBlock->clipplane[Index][2];
3581 pPlane[3] = This->stateBlock->clipplane[Index][3];
3582 return WINED3D_OK;
3585 /*****
3586 * Get / Set Clip Plane Status
3587 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3588 *****/
3589 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3590 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3591 FIXME("(%p) : stub\n", This);
3592 if (NULL == pClipStatus) {
3593 return WINED3DERR_INVALIDCALL;
3595 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3596 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3597 return WINED3D_OK;
3600 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3601 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3602 FIXME("(%p) : stub\n", This);
3603 if (NULL == pClipStatus) {
3604 return WINED3DERR_INVALIDCALL;
3606 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3607 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3608 return WINED3D_OK;
3611 /*****
3612 * Get / Set Material
3613 *****/
3614 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3615 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3617 This->updateStateBlock->changed.material = TRUE;
3618 This->updateStateBlock->material = *pMaterial;
3620 /* Handle recording of state blocks */
3621 if (This->isRecordingState) {
3622 TRACE("Recording... not performing anything\n");
3623 return WINED3D_OK;
3626 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3627 return WINED3D_OK;
3630 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3632 *pMaterial = This->updateStateBlock->material;
3633 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3634 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3635 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3636 pMaterial->Ambient.b, pMaterial->Ambient.a);
3637 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3638 pMaterial->Specular.b, pMaterial->Specular.a);
3639 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3640 pMaterial->Emissive.b, pMaterial->Emissive.a);
3641 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3643 return WINED3D_OK;
3646 /*****
3647 * Get / Set Indices
3648 *****/
3649 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DBuffer* pIndexData, WINED3DFORMAT fmt) {
3650 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3651 IWineD3DBuffer *oldIdxs;
3653 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3654 oldIdxs = This->updateStateBlock->pIndexData;
3656 This->updateStateBlock->changed.indices = TRUE;
3657 This->updateStateBlock->pIndexData = pIndexData;
3658 This->updateStateBlock->IndexFmt = fmt;
3660 /* Handle recording of state blocks */
3661 if (This->isRecordingState) {
3662 TRACE("Recording... not performing anything\n");
3663 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
3664 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
3665 return WINED3D_OK;
3668 if(oldIdxs != pIndexData) {
3669 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3670 if(pIndexData) {
3671 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
3672 IWineD3DBuffer_AddRef(pIndexData);
3674 if(oldIdxs) {
3675 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
3676 IWineD3DBuffer_Release(oldIdxs);
3680 return WINED3D_OK;
3683 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DBuffer** ppIndexData) {
3684 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3686 *ppIndexData = This->stateBlock->pIndexData;
3688 /* up ref count on ppindexdata */
3689 if (*ppIndexData) {
3690 IWineD3DBuffer_AddRef(*ppIndexData);
3691 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3692 }else{
3693 TRACE("(%p) No index data set\n", This);
3695 TRACE("Returning %p\n", *ppIndexData);
3697 return WINED3D_OK;
3700 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3701 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3702 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3703 TRACE("(%p)->(%d)\n", This, BaseIndex);
3705 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3706 TRACE("Application is setting the old value over, nothing to do\n");
3707 return WINED3D_OK;
3710 This->updateStateBlock->baseVertexIndex = BaseIndex;
3712 if (This->isRecordingState) {
3713 TRACE("Recording... not performing anything\n");
3714 return WINED3D_OK;
3716 /* The base vertex index affects the stream sources */
3717 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3718 return WINED3D_OK;
3721 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3722 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3723 TRACE("(%p) : base_index %p\n", This, base_index);
3725 *base_index = This->stateBlock->baseVertexIndex;
3727 TRACE("Returning %u\n", *base_index);
3729 return WINED3D_OK;
3732 /*****
3733 * Get / Set Viewports
3734 *****/
3735 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3736 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3738 TRACE("(%p)\n", This);
3739 This->updateStateBlock->changed.viewport = TRUE;
3740 This->updateStateBlock->viewport = *pViewport;
3742 /* Handle recording of state blocks */
3743 if (This->isRecordingState) {
3744 TRACE("Recording... not performing anything\n");
3745 return WINED3D_OK;
3748 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3749 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3751 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3752 return WINED3D_OK;
3756 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3757 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3758 TRACE("(%p)\n", This);
3759 *pViewport = This->stateBlock->viewport;
3760 return WINED3D_OK;
3763 /*****
3764 * Get / Set Render States
3765 * TODO: Verify against dx9 definitions
3766 *****/
3767 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3769 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3770 DWORD oldValue = This->stateBlock->renderState[State];
3772 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3774 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3775 This->updateStateBlock->renderState[State] = Value;
3777 /* Handle recording of state blocks */
3778 if (This->isRecordingState) {
3779 TRACE("Recording... not performing anything\n");
3780 return WINED3D_OK;
3783 /* Compared here and not before the assignment to allow proper stateblock recording */
3784 if(Value == oldValue) {
3785 TRACE("Application is setting the old value over, nothing to do\n");
3786 } else {
3787 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3790 return WINED3D_OK;
3793 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3794 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3795 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3796 *pValue = This->stateBlock->renderState[State];
3797 return WINED3D_OK;
3800 /*****
3801 * Get / Set Sampler States
3802 * TODO: Verify against dx9 definitions
3803 *****/
3805 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3806 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3807 DWORD oldValue;
3809 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3810 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3812 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3813 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3816 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3817 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3818 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3821 * SetSampler is designed to allow for more than the standard up to 8 textures
3822 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3823 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3825 * http://developer.nvidia.com/object/General_FAQ.html#t6
3827 * There are two new settings for GForce
3828 * the sampler one:
3829 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3830 * and the texture one:
3831 * GL_MAX_TEXTURE_COORDS_ARB.
3832 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3833 ******************/
3835 oldValue = This->stateBlock->samplerState[Sampler][Type];
3836 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3837 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3839 /* Handle recording of state blocks */
3840 if (This->isRecordingState) {
3841 TRACE("Recording... not performing anything\n");
3842 return WINED3D_OK;
3845 if(oldValue == Value) {
3846 TRACE("Application is setting the old value over, nothing to do\n");
3847 return WINED3D_OK;
3850 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3852 return WINED3D_OK;
3855 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3856 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3858 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3859 This, Sampler, debug_d3dsamplerstate(Type), Type);
3861 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3862 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3865 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3866 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3867 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3869 *Value = This->stateBlock->samplerState[Sampler][Type];
3870 TRACE("(%p) : Returning %#x\n", This, *Value);
3872 return WINED3D_OK;
3875 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3876 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3878 This->updateStateBlock->changed.scissorRect = TRUE;
3879 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3880 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3881 return WINED3D_OK;
3883 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3885 if(This->isRecordingState) {
3886 TRACE("Recording... not performing anything\n");
3887 return WINED3D_OK;
3890 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3892 return WINED3D_OK;
3895 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3898 *pRect = This->updateStateBlock->scissorRect;
3899 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3900 return WINED3D_OK;
3903 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3904 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3905 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3907 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3909 This->updateStateBlock->vertexDecl = pDecl;
3910 This->updateStateBlock->changed.vertexDecl = TRUE;
3912 if (This->isRecordingState) {
3913 TRACE("Recording... not performing anything\n");
3914 return WINED3D_OK;
3915 } else if(pDecl == oldDecl) {
3916 /* Checked after the assignment to allow proper stateblock recording */
3917 TRACE("Application is setting the old declaration over, nothing to do\n");
3918 return WINED3D_OK;
3921 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3922 return WINED3D_OK;
3925 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3928 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3930 *ppDecl = This->stateBlock->vertexDecl;
3931 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3932 return WINED3D_OK;
3935 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3936 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3937 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3939 This->updateStateBlock->vertexShader = pShader;
3940 This->updateStateBlock->changed.vertexShader = TRUE;
3942 if (This->isRecordingState) {
3943 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3944 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3945 TRACE("Recording... not performing anything\n");
3946 return WINED3D_OK;
3947 } else if(oldShader == pShader) {
3948 /* Checked here to allow proper stateblock recording */
3949 TRACE("App is setting the old shader over, nothing to do\n");
3950 return WINED3D_OK;
3953 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3954 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3955 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3957 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3959 return WINED3D_OK;
3962 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3963 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3965 if (NULL == ppShader) {
3966 return WINED3DERR_INVALIDCALL;
3968 *ppShader = This->stateBlock->vertexShader;
3969 if( NULL != *ppShader)
3970 IWineD3DVertexShader_AddRef(*ppShader);
3972 TRACE("(%p) : returning %p\n", This, *ppShader);
3973 return WINED3D_OK;
3976 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3977 IWineD3DDevice *iface,
3978 UINT start,
3979 CONST BOOL *srcData,
3980 UINT count) {
3982 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3983 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3985 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3986 iface, srcData, start, count);
3988 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3990 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3991 for (i = 0; i < cnt; i++)
3992 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3994 for (i = start; i < cnt + start; ++i) {
3995 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3998 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
4000 return WINED3D_OK;
4003 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
4004 IWineD3DDevice *iface,
4005 UINT start,
4006 BOOL *dstData,
4007 UINT count) {
4009 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4010 int cnt = min(count, MAX_CONST_B - start);
4012 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4013 iface, dstData, start, count);
4015 if (dstData == NULL || cnt < 0)
4016 return WINED3DERR_INVALIDCALL;
4018 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
4019 return WINED3D_OK;
4022 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
4023 IWineD3DDevice *iface,
4024 UINT start,
4025 CONST int *srcData,
4026 UINT count) {
4028 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4029 unsigned int i, cnt = min(count, MAX_CONST_I - start);
4031 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4032 iface, srcData, start, count);
4034 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
4036 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4037 for (i = 0; i < cnt; i++)
4038 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4039 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4041 for (i = start; i < cnt + start; ++i) {
4042 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
4045 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
4047 return WINED3D_OK;
4050 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
4051 IWineD3DDevice *iface,
4052 UINT start,
4053 int *dstData,
4054 UINT count) {
4056 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4057 int cnt = min(count, MAX_CONST_I - start);
4059 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4060 iface, dstData, start, count);
4062 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
4063 return WINED3DERR_INVALIDCALL;
4065 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4066 return WINED3D_OK;
4069 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
4070 IWineD3DDevice *iface,
4071 UINT start,
4072 CONST float *srcData,
4073 UINT count) {
4075 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4076 UINT i;
4078 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4079 iface, srcData, start, count);
4081 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4082 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
4083 return WINED3DERR_INVALIDCALL;
4085 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4086 if(TRACE_ON(d3d)) {
4087 for (i = 0; i < count; i++)
4088 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4089 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4092 if (!This->isRecordingState)
4094 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
4095 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
4098 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
4099 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
4101 return WINED3D_OK;
4104 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
4105 IWineD3DDevice *iface,
4106 UINT start,
4107 float *dstData,
4108 UINT count) {
4110 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4111 int cnt = min(count, This->d3d_vshader_constantF - start);
4113 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4114 iface, dstData, start, count);
4116 if (dstData == NULL || cnt < 0)
4117 return WINED3DERR_INVALIDCALL;
4119 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4120 return WINED3D_OK;
4123 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
4124 DWORD i;
4125 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
4127 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
4131 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
4132 int i = This->rev_tex_unit_map[unit];
4133 int j = This->texUnitMap[stage];
4135 This->texUnitMap[stage] = unit;
4136 if (i != -1 && i != stage) {
4137 This->texUnitMap[i] = -1;
4140 This->rev_tex_unit_map[unit] = stage;
4141 if (j != -1 && j != unit) {
4142 This->rev_tex_unit_map[j] = -1;
4146 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
4147 int i;
4149 This->fixed_function_usage_map = 0;
4150 for (i = 0; i < MAX_TEXTURES; ++i) {
4151 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
4152 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
4153 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
4154 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
4155 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
4156 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
4157 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
4158 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
4160 if (color_op == WINED3DTOP_DISABLE) {
4161 /* Not used, and disable higher stages */
4162 break;
4165 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
4166 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
4167 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
4168 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
4169 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
4170 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
4171 This->fixed_function_usage_map |= (1 << i);
4174 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
4175 This->fixed_function_usage_map |= (1 << (i + 1));
4180 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
4181 unsigned int i, tex;
4182 WORD ffu_map;
4184 device_update_fixed_function_usage_map(This);
4185 ffu_map = This->fixed_function_usage_map;
4187 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
4188 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
4189 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
4191 if (!(ffu_map & 1)) continue;
4193 if (This->texUnitMap[i] != i) {
4194 device_map_stage(This, i, i);
4195 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
4196 markTextureStagesDirty(This, i);
4199 return;
4202 /* Now work out the mapping */
4203 tex = 0;
4204 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
4206 if (!(ffu_map & 1)) continue;
4208 if (This->texUnitMap[i] != tex) {
4209 device_map_stage(This, i, tex);
4210 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
4211 markTextureStagesDirty(This, i);
4214 ++tex;
4218 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
4219 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
4220 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
4221 unsigned int i;
4223 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
4224 if (sampler_type[i] && This->texUnitMap[i] != i)
4226 device_map_stage(This, i, i);
4227 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
4228 if (i < MAX_TEXTURES) {
4229 markTextureStagesDirty(This, i);
4235 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
4236 const DWORD *vshader_sampler_tokens, int unit)
4238 int current_mapping = This->rev_tex_unit_map[unit];
4240 if (current_mapping == -1) {
4241 /* Not currently used */
4242 return TRUE;
4245 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
4246 /* Used by a fragment sampler */
4248 if (!pshader_sampler_tokens) {
4249 /* No pixel shader, check fixed function */
4250 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
4253 /* Pixel shader, check the shader's sampler map */
4254 return !pshader_sampler_tokens[current_mapping];
4257 /* Used by a vertex sampler */
4258 return !vshader_sampler_tokens[current_mapping];
4261 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
4262 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
4263 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
4264 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
4265 int start = GL_LIMITS(combined_samplers) - 1;
4266 int i;
4268 if (ps) {
4269 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
4271 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
4272 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
4273 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
4276 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
4277 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
4278 if (vshader_sampler_type[i])
4280 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
4282 /* Already mapped somewhere */
4283 continue;
4286 while (start >= 0) {
4287 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
4289 device_map_stage(This, vsampler_idx, start);
4290 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
4292 --start;
4293 break;
4296 --start;
4302 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
4303 BOOL vs = use_vs(This->stateBlock);
4304 BOOL ps = use_ps(This->stateBlock);
4306 * Rules are:
4307 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
4308 * that would be really messy and require shader recompilation
4309 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
4310 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
4312 if (ps) {
4313 device_map_psamplers(This);
4314 } else {
4315 device_map_fixed_function_samplers(This);
4318 if (vs) {
4319 device_map_vsamplers(This, ps);
4323 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4325 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4326 This->updateStateBlock->pixelShader = pShader;
4327 This->updateStateBlock->changed.pixelShader = TRUE;
4329 /* Handle recording of state blocks */
4330 if (This->isRecordingState) {
4331 TRACE("Recording... not performing anything\n");
4334 if (This->isRecordingState) {
4335 TRACE("Recording... not performing anything\n");
4336 if(pShader) IWineD3DPixelShader_AddRef(pShader);
4337 if(oldShader) IWineD3DPixelShader_Release(oldShader);
4338 return WINED3D_OK;
4341 if(pShader == oldShader) {
4342 TRACE("App is setting the old pixel shader over, nothing to do\n");
4343 return WINED3D_OK;
4346 if(pShader) IWineD3DPixelShader_AddRef(pShader);
4347 if(oldShader) IWineD3DPixelShader_Release(oldShader);
4349 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4350 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4352 return WINED3D_OK;
4355 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4356 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4358 if (NULL == ppShader) {
4359 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4360 return WINED3DERR_INVALIDCALL;
4363 *ppShader = This->stateBlock->pixelShader;
4364 if (NULL != *ppShader) {
4365 IWineD3DPixelShader_AddRef(*ppShader);
4367 TRACE("(%p) : returning %p\n", This, *ppShader);
4368 return WINED3D_OK;
4371 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4372 IWineD3DDevice *iface,
4373 UINT start,
4374 CONST BOOL *srcData,
4375 UINT count) {
4377 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4378 unsigned int i, cnt = min(count, MAX_CONST_B - start);
4380 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
4381 iface, srcData, start, count);
4383 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
4385 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4386 for (i = 0; i < cnt; i++)
4387 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4389 for (i = start; i < cnt + start; ++i) {
4390 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
4393 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4395 return WINED3D_OK;
4398 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4399 IWineD3DDevice *iface,
4400 UINT start,
4401 BOOL *dstData,
4402 UINT count) {
4404 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4405 int cnt = min(count, MAX_CONST_B - start);
4407 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4408 iface, dstData, start, count);
4410 if (dstData == NULL || cnt < 0)
4411 return WINED3DERR_INVALIDCALL;
4413 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4414 return WINED3D_OK;
4417 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4418 IWineD3DDevice *iface,
4419 UINT start,
4420 CONST int *srcData,
4421 UINT count) {
4423 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4424 unsigned int i, cnt = min(count, MAX_CONST_I - start);
4426 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
4427 iface, srcData, start, count);
4429 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
4431 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4432 for (i = 0; i < cnt; i++)
4433 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4434 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4436 for (i = start; i < cnt + start; ++i) {
4437 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
4440 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4442 return WINED3D_OK;
4445 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4446 IWineD3DDevice *iface,
4447 UINT start,
4448 int *dstData,
4449 UINT count) {
4451 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4452 int cnt = min(count, MAX_CONST_I - start);
4454 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4455 iface, dstData, start, count);
4457 if (dstData == NULL || cnt < 0)
4458 return WINED3DERR_INVALIDCALL;
4460 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4461 return WINED3D_OK;
4464 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4465 IWineD3DDevice *iface,
4466 UINT start,
4467 CONST float *srcData,
4468 UINT count) {
4470 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4471 UINT i;
4473 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4474 iface, srcData, start, count);
4476 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4477 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
4478 return WINED3DERR_INVALIDCALL;
4480 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4481 if(TRACE_ON(d3d)) {
4482 for (i = 0; i < count; i++)
4483 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4484 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4487 if (!This->isRecordingState)
4489 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
4490 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4493 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
4494 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
4496 return WINED3D_OK;
4499 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4500 IWineD3DDevice *iface,
4501 UINT start,
4502 float *dstData,
4503 UINT count) {
4505 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4506 int cnt = min(count, This->d3d_pshader_constantF - start);
4508 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4509 iface, dstData, start, count);
4511 if (dstData == NULL || cnt < 0)
4512 return WINED3DERR_INVALIDCALL;
4514 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4515 return WINED3D_OK;
4518 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4519 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4520 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
4521 DWORD DestFVF)
4523 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4524 unsigned int i;
4525 WINED3DVIEWPORT vp;
4526 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4527 BOOL doClip;
4528 DWORD numTextures;
4530 if (stream_info->elements[WINED3D_FFP_NORMAL].data)
4532 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4535 if (!stream_info->elements[WINED3D_FFP_POSITION].data)
4537 ERR("Source has no position mask\n");
4538 return WINED3DERR_INVALIDCALL;
4541 /* We might access VBOs from this code, so hold the lock */
4542 ENTER_GL();
4544 if (dest->resource.allocatedMemory == NULL) {
4545 buffer_get_sysmem(dest);
4548 /* Get a pointer into the destination vbo(create one if none exists) and
4549 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4551 if (!dest->buffer_object && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT))
4553 dest->flags |= WINED3D_BUFFER_CREATEBO;
4554 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
4557 if (dest->buffer_object)
4559 unsigned char extrabytes = 0;
4560 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4561 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4562 * this may write 4 extra bytes beyond the area that should be written
4564 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4565 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4566 if(!dest_conv_addr) {
4567 ERR("Out of memory\n");
4568 /* Continue without storing converted vertices */
4570 dest_conv = dest_conv_addr;
4573 /* Should I clip?
4574 * a) WINED3DRS_CLIPPING is enabled
4575 * b) WINED3DVOP_CLIP is passed
4577 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4578 static BOOL warned = FALSE;
4580 * The clipping code is not quite correct. Some things need
4581 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4582 * so disable clipping for now.
4583 * (The graphics in Half-Life are broken, and my processvertices
4584 * test crashes with IDirect3DDevice3)
4585 doClip = TRUE;
4587 doClip = FALSE;
4588 if(!warned) {
4589 warned = TRUE;
4590 FIXME("Clipping is broken and disabled for now\n");
4592 } else doClip = FALSE;
4593 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4595 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4596 WINED3DTS_VIEW,
4597 &view_mat);
4598 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4599 WINED3DTS_PROJECTION,
4600 &proj_mat);
4601 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4602 WINED3DTS_WORLDMATRIX(0),
4603 &world_mat);
4605 TRACE("View mat:\n");
4606 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);
4607 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);
4608 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);
4609 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);
4611 TRACE("Proj mat:\n");
4612 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);
4613 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);
4614 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);
4615 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);
4617 TRACE("World mat:\n");
4618 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);
4619 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);
4620 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);
4621 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);
4623 /* Get the viewport */
4624 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4625 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4626 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4628 multiply_matrix(&mat,&view_mat,&world_mat);
4629 multiply_matrix(&mat,&proj_mat,&mat);
4631 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4633 for (i = 0; i < dwCount; i+= 1) {
4634 unsigned int tex_index;
4636 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4637 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4638 /* The position first */
4639 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
4640 const float *p = (const float *)(element->data + i * element->stride);
4641 float x, y, z, rhw;
4642 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4644 /* Multiplication with world, view and projection matrix */
4645 x = (p[0] * mat.u.s._11) + (p[1] * mat.u.s._21) + (p[2] * mat.u.s._31) + (1.0 * mat.u.s._41);
4646 y = (p[0] * mat.u.s._12) + (p[1] * mat.u.s._22) + (p[2] * mat.u.s._32) + (1.0 * mat.u.s._42);
4647 z = (p[0] * mat.u.s._13) + (p[1] * mat.u.s._23) + (p[2] * mat.u.s._33) + (1.0 * mat.u.s._43);
4648 rhw = (p[0] * mat.u.s._14) + (p[1] * mat.u.s._24) + (p[2] * mat.u.s._34) + (1.0 * mat.u.s._44);
4650 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4652 /* WARNING: The following things are taken from d3d7 and were not yet checked
4653 * against d3d8 or d3d9!
4656 /* Clipping conditions: From msdn
4658 * A vertex is clipped if it does not match the following requirements
4659 * -rhw < x <= rhw
4660 * -rhw < y <= rhw
4661 * 0 < z <= rhw
4662 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4664 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4665 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4669 if( !doClip ||
4670 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4671 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4672 ( rhw > eps ) ) ) {
4674 /* "Normal" viewport transformation (not clipped)
4675 * 1) The values are divided by rhw
4676 * 2) The y axis is negative, so multiply it with -1
4677 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4678 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4679 * 4) Multiply x with Width/2 and add Width/2
4680 * 5) The same for the height
4681 * 6) Add the viewpoint X and Y to the 2D coordinates and
4682 * The minimum Z value to z
4683 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4685 * Well, basically it's simply a linear transformation into viewport
4686 * coordinates
4689 x /= rhw;
4690 y /= rhw;
4691 z /= rhw;
4693 y *= -1;
4695 x *= vp.Width / 2;
4696 y *= vp.Height / 2;
4697 z *= vp.MaxZ - vp.MinZ;
4699 x += vp.Width / 2 + vp.X;
4700 y += vp.Height / 2 + vp.Y;
4701 z += vp.MinZ;
4703 rhw = 1 / rhw;
4704 } else {
4705 /* That vertex got clipped
4706 * Contrary to OpenGL it is not dropped completely, it just
4707 * undergoes a different calculation.
4709 TRACE("Vertex got clipped\n");
4710 x += rhw;
4711 y += rhw;
4713 x /= 2;
4714 y /= 2;
4716 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4717 * outside of the main vertex buffer memory. That needs some more
4718 * investigation...
4722 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4725 ( (float *) dest_ptr)[0] = x;
4726 ( (float *) dest_ptr)[1] = y;
4727 ( (float *) dest_ptr)[2] = z;
4728 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4730 dest_ptr += 3 * sizeof(float);
4732 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4733 dest_ptr += sizeof(float);
4736 if(dest_conv) {
4737 float w = 1 / rhw;
4738 ( (float *) dest_conv)[0] = x * w;
4739 ( (float *) dest_conv)[1] = y * w;
4740 ( (float *) dest_conv)[2] = z * w;
4741 ( (float *) dest_conv)[3] = w;
4743 dest_conv += 3 * sizeof(float);
4745 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4746 dest_conv += sizeof(float);
4750 if (DestFVF & WINED3DFVF_PSIZE) {
4751 dest_ptr += sizeof(DWORD);
4752 if(dest_conv) dest_conv += sizeof(DWORD);
4754 if (DestFVF & WINED3DFVF_NORMAL) {
4755 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4756 const float *normal = (const float *)(element->data + i * element->stride);
4757 /* AFAIK this should go into the lighting information */
4758 FIXME("Didn't expect the destination to have a normal\n");
4759 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4760 if(dest_conv) {
4761 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4765 if (DestFVF & WINED3DFVF_DIFFUSE) {
4766 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4767 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4768 if(!color_d) {
4769 static BOOL warned = FALSE;
4771 if(!warned) {
4772 ERR("No diffuse color in source, but destination has one\n");
4773 warned = TRUE;
4776 *( (DWORD *) dest_ptr) = 0xffffffff;
4777 dest_ptr += sizeof(DWORD);
4779 if(dest_conv) {
4780 *( (DWORD *) dest_conv) = 0xffffffff;
4781 dest_conv += sizeof(DWORD);
4784 else {
4785 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4786 if(dest_conv) {
4787 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4788 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4789 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4790 dest_conv += sizeof(DWORD);
4795 if (DestFVF & WINED3DFVF_SPECULAR) {
4796 /* What's the color value in the feedback buffer? */
4797 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4798 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4799 if(!color_s) {
4800 static BOOL warned = FALSE;
4802 if(!warned) {
4803 ERR("No specular color in source, but destination has one\n");
4804 warned = TRUE;
4807 *( (DWORD *) dest_ptr) = 0xFF000000;
4808 dest_ptr += sizeof(DWORD);
4810 if(dest_conv) {
4811 *( (DWORD *) dest_conv) = 0xFF000000;
4812 dest_conv += sizeof(DWORD);
4815 else {
4816 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4817 if(dest_conv) {
4818 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4819 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4820 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4821 dest_conv += sizeof(DWORD);
4826 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4827 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4828 const float *tex_coord = (const float *)(element->data + i * element->stride);
4829 if(!tex_coord) {
4830 ERR("No source texture, but destination requests one\n");
4831 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4832 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4834 else {
4835 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4836 if(dest_conv) {
4837 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4843 if(dest_conv) {
4844 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4845 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4846 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4847 dwCount * get_flexible_vertex_size(DestFVF),
4848 dest_conv_addr));
4849 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4850 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4853 LEAVE_GL();
4855 return WINED3D_OK;
4857 #undef copy_and_next
4859 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4860 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4861 DWORD DestFVF)
4863 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4864 struct wined3d_stream_info stream_info;
4865 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4866 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4868 if(pVertexDecl) {
4869 ERR("Output vertex declaration not implemented yet\n");
4872 /* Need any context to write to the vbo. */
4873 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4875 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4876 * control the streamIsUP flag, thus restore it afterwards.
4878 This->stateBlock->streamIsUP = FALSE;
4879 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4880 This->stateBlock->streamIsUP = streamWasUP;
4882 if(vbo || SrcStartIndex) {
4883 unsigned int i;
4884 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4885 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4887 * Also get the start index in, but only loop over all elements if there's something to add at all.
4889 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4891 struct wined3d_stream_info_element *e = &stream_info.elements[i];
4892 if (e->buffer_object)
4894 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
4895 e->buffer_object = 0;
4896 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
4897 ENTER_GL();
4898 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4899 vb->buffer_object = 0;
4900 LEAVE_GL();
4902 if (e->data) e->data += e->stride * SrcStartIndex;
4906 return process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4907 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4910 /*****
4911 * Get / Set Texture Stage States
4912 * TODO: Verify against dx9 definitions
4913 *****/
4914 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4915 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4916 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4918 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4920 if (Stage >= MAX_TEXTURES) {
4921 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4922 return WINED3D_OK;
4925 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4926 This->updateStateBlock->textureState[Stage][Type] = Value;
4928 if (This->isRecordingState) {
4929 TRACE("Recording... not performing anything\n");
4930 return WINED3D_OK;
4933 /* Checked after the assignments to allow proper stateblock recording */
4934 if(oldValue == Value) {
4935 TRACE("App is setting the old value over, nothing to do\n");
4936 return WINED3D_OK;
4939 if(Stage > This->stateBlock->lowest_disabled_stage &&
4940 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4941 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4942 * Changes in other states are important on disabled stages too
4944 return WINED3D_OK;
4947 if(Type == WINED3DTSS_COLOROP) {
4948 unsigned int i;
4950 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4951 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4952 * they have to be disabled
4954 * The current stage is dirtified below.
4956 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4957 TRACE("Additionally dirtifying stage %u\n", i);
4958 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4960 This->stateBlock->lowest_disabled_stage = Stage;
4961 TRACE("New lowest disabled: %u\n", Stage);
4962 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4963 /* Previously disabled stage enabled. Stages above it may need enabling
4964 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4965 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4967 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4970 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4971 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4972 break;
4974 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4975 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4977 This->stateBlock->lowest_disabled_stage = i;
4978 TRACE("New lowest disabled: %u\n", i);
4982 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4984 return WINED3D_OK;
4987 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4988 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4989 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4990 *pValue = This->updateStateBlock->textureState[Stage][Type];
4991 return WINED3D_OK;
4994 /*****
4995 * Get / Set Texture
4996 *****/
4997 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4998 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4999 IWineD3DBaseTexture *oldTexture;
5001 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
5003 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
5004 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
5007 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
5008 ERR("Current stage overflows textures array (stage %d)\n", Stage);
5009 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
5012 oldTexture = This->updateStateBlock->textures[Stage];
5014 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
5015 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
5017 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
5018 return WINED3DERR_INVALIDCALL;
5021 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
5022 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
5024 This->updateStateBlock->changed.textures |= 1 << Stage;
5025 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
5026 This->updateStateBlock->textures[Stage] = pTexture;
5028 /* Handle recording of state blocks */
5029 if (This->isRecordingState) {
5030 TRACE("Recording... not performing anything\n");
5031 return WINED3D_OK;
5034 if(oldTexture == pTexture) {
5035 TRACE("App is setting the same texture again, nothing to do\n");
5036 return WINED3D_OK;
5039 /** NOTE: MSDN says that setTexture increases the reference count,
5040 * and that the application must set the texture back to null (or have a leaky application),
5041 * This means we should pass the refcount up to the parent
5042 *******************************/
5043 if (NULL != This->updateStateBlock->textures[Stage]) {
5044 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
5045 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
5046 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
5048 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
5050 if (!oldTexture || dimensions != IWineD3DBaseTexture_GetTextureDimensions(oldTexture))
5052 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
5055 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
5056 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
5057 * so the COLOROP and ALPHAOP have to be dirtified.
5059 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
5060 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
5062 if(bindCount == 1) {
5063 new->baseTexture.sampler = Stage;
5065 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
5069 if (NULL != oldTexture) {
5070 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
5071 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
5073 IWineD3DBaseTexture_Release(oldTexture);
5074 if(pTexture == NULL && Stage < MAX_TEXTURES) {
5075 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
5076 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
5079 if(bindCount && old->baseTexture.sampler == Stage) {
5080 int i;
5081 /* Have to do a search for the other sampler(s) where the texture is bound to
5082 * Shouldn't happen as long as apps bind a texture only to one stage
5084 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
5085 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5086 if(This->updateStateBlock->textures[i] == oldTexture) {
5087 old->baseTexture.sampler = i;
5088 break;
5094 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
5096 return WINED3D_OK;
5099 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
5100 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5102 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
5104 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
5105 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
5108 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
5109 ERR("Current stage overflows textures array (stage %d)\n", Stage);
5110 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
5113 *ppTexture=This->stateBlock->textures[Stage];
5114 if (*ppTexture)
5115 IWineD3DBaseTexture_AddRef(*ppTexture);
5117 TRACE("(%p) : Returning %p\n", This, *ppTexture);
5119 return WINED3D_OK;
5122 /*****
5123 * Get Back Buffer
5124 *****/
5125 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
5126 IWineD3DSurface **ppBackBuffer) {
5127 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5128 IWineD3DSwapChain *swapChain;
5129 HRESULT hr;
5131 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
5133 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5134 if (hr == WINED3D_OK) {
5135 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
5136 IWineD3DSwapChain_Release(swapChain);
5137 } else {
5138 *ppBackBuffer = NULL;
5140 return hr;
5143 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
5144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5145 WARN("(%p) : stub, calling idirect3d for now\n", This);
5146 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
5149 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
5150 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5151 IWineD3DSwapChain *swapChain;
5152 HRESULT hr;
5154 if(iSwapChain > 0) {
5155 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5156 if (hr == WINED3D_OK) {
5157 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
5158 IWineD3DSwapChain_Release(swapChain);
5159 } else {
5160 FIXME("(%p) Error getting display mode\n", This);
5162 } else {
5163 /* Don't read the real display mode,
5164 but return the stored mode instead. X11 can't change the color
5165 depth, and some apps are pretty angry if they SetDisplayMode from
5166 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
5168 Also don't relay to the swapchain because with ddraw it's possible
5169 that there isn't a swapchain at all */
5170 pMode->Width = This->ddraw_width;
5171 pMode->Height = This->ddraw_height;
5172 pMode->Format = This->ddraw_format;
5173 pMode->RefreshRate = 0;
5174 hr = WINED3D_OK;
5177 return hr;
5180 /*****
5181 * Stateblock related functions
5182 *****/
5184 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
5185 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5186 IWineD3DStateBlock *stateblock;
5187 HRESULT hr;
5189 TRACE("(%p)\n", This);
5191 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
5193 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
5194 if (FAILED(hr)) return hr;
5196 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
5197 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
5198 This->isRecordingState = TRUE;
5200 TRACE("(%p) recording stateblock %p\n", This, stateblock);
5202 return WINED3D_OK;
5205 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
5206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5207 unsigned int i, j;
5208 IWineD3DStateBlockImpl *object = This->updateStateBlock;
5210 if (!This->isRecordingState) {
5211 WARN("(%p) not recording! returning error\n", This);
5212 *ppStateBlock = NULL;
5213 return WINED3DERR_INVALIDCALL;
5216 for (i = 0; i <= WINEHIGHEST_RENDER_STATE >> 5; ++i)
5218 DWORD map = object->changed.renderState[i];
5219 for (j = 0; map; map >>= 1, ++j)
5221 if (!(map & 1)) continue;
5223 object->contained_render_states[object->num_contained_render_states++] = (i << 5) | j;
5227 for (i = 0; i <= HIGHEST_TRANSFORMSTATE >> 5; ++i)
5229 DWORD map = object->changed.transform[i];
5230 for (j = 0; map; map >>= 1, ++j)
5232 if (!(map & 1)) continue;
5234 object->contained_transform_states[object->num_contained_transform_states++] = (i << 5) | j;
5237 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
5238 if(object->changed.vertexShaderConstantsF[i]) {
5239 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
5240 object->num_contained_vs_consts_f++;
5243 for(i = 0; i < MAX_CONST_I; i++) {
5244 if (object->changed.vertexShaderConstantsI & (1 << i))
5246 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
5247 object->num_contained_vs_consts_i++;
5250 for(i = 0; i < MAX_CONST_B; i++) {
5251 if (object->changed.vertexShaderConstantsB & (1 << i))
5253 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
5254 object->num_contained_vs_consts_b++;
5257 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
5259 if (object->changed.pixelShaderConstantsF[i])
5261 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
5262 ++object->num_contained_ps_consts_f;
5265 for(i = 0; i < MAX_CONST_I; i++) {
5266 if (object->changed.pixelShaderConstantsI & (1 << i))
5268 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
5269 object->num_contained_ps_consts_i++;
5272 for(i = 0; i < MAX_CONST_B; i++) {
5273 if (object->changed.pixelShaderConstantsB & (1 << i))
5275 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
5276 object->num_contained_ps_consts_b++;
5279 for(i = 0; i < MAX_TEXTURES; i++) {
5280 DWORD map = object->changed.textureState[i];
5282 for(j = 0; map; map >>= 1, ++j)
5284 if (!(map & 1)) continue;
5286 object->contained_tss_states[object->num_contained_tss_states].stage = i;
5287 object->contained_tss_states[object->num_contained_tss_states].state = j;
5288 ++object->num_contained_tss_states;
5291 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
5292 DWORD map = object->changed.samplerState[i];
5294 for (j = 0; map; map >>= 1, ++j)
5296 if (!(map & 1)) continue;
5298 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
5299 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
5300 ++object->num_contained_sampler_states;
5304 *ppStateBlock = (IWineD3DStateBlock*) object;
5305 This->isRecordingState = FALSE;
5306 This->updateStateBlock = This->stateBlock;
5307 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5308 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5309 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5310 return WINED3D_OK;
5313 /*****
5314 * Scene related functions
5315 *****/
5316 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5317 /* At the moment we have no need for any functionality at the beginning
5318 of a scene */
5319 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5320 TRACE("(%p)\n", This);
5322 if(This->inScene) {
5323 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
5324 return WINED3DERR_INVALIDCALL;
5326 This->inScene = TRUE;
5327 return WINED3D_OK;
5330 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5331 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5332 TRACE("(%p)\n", This);
5334 if(!This->inScene) {
5335 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
5336 return WINED3DERR_INVALIDCALL;
5339 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5340 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5341 glFlush();
5342 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
5343 * fails
5346 This->inScene = FALSE;
5347 return WINED3D_OK;
5350 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5351 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5352 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5353 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5354 IWineD3DSwapChain *swapChain = NULL;
5355 int i;
5356 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5358 TRACE("(%p) Presenting the frame\n", This);
5360 for(i = 0 ; i < swapchains ; i ++) {
5362 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
5363 TRACE("presentinng chain %d, %p\n", i, swapChain);
5364 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5365 IWineD3DSwapChain_Release(swapChain);
5368 return WINED3D_OK;
5371 /* Not called from the VTable (internal subroutine) */
5372 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
5373 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
5374 float Z, DWORD Stencil) {
5375 GLbitfield glMask = 0;
5376 unsigned int i;
5377 WINED3DRECT curRect;
5378 RECT vp_rect;
5379 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
5380 UINT drawable_width, drawable_height;
5381 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
5382 IWineD3DSwapChainImpl *swapchain = NULL;
5384 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5385 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5386 * for the cleared parts, and the untouched parts.
5388 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5389 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5390 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5391 * checking all this if the dest surface is in the drawable anyway.
5393 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5394 while(1) {
5395 if(vp->X != 0 || vp->Y != 0 ||
5396 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5397 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5398 break;
5400 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5401 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5402 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5403 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5404 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5405 break;
5407 if(Count > 0 && pRects && (
5408 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5409 pRects[0].x2 < target->currentDesc.Width ||
5410 pRects[0].y2 < target->currentDesc.Height)) {
5411 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5412 break;
5414 break;
5418 target->get_drawable_size(target, &drawable_width, &drawable_height);
5420 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5421 ENTER_GL();
5423 /* Only set the values up once, as they are not changing */
5424 if (Flags & WINED3DCLEAR_STENCIL) {
5425 glClearStencil(Stencil);
5426 checkGLcall("glClearStencil");
5427 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5428 glStencilMask(0xFFFFFFFF);
5431 if (Flags & WINED3DCLEAR_ZBUFFER) {
5432 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5433 glDepthMask(GL_TRUE);
5434 glClearDepth(Z);
5435 checkGLcall("glClearDepth");
5436 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5437 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5439 if (vp->X != 0 || vp->Y != 0 ||
5440 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5441 surface_load_ds_location(This->stencilBufferTarget, location);
5443 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5444 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5445 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5446 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5447 surface_load_ds_location(This->stencilBufferTarget, location);
5449 else if (Count > 0 && pRects && (
5450 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5451 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5452 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5453 surface_load_ds_location(This->stencilBufferTarget, location);
5457 if (Flags & WINED3DCLEAR_TARGET) {
5458 TRACE("Clearing screen with glClear to color %x\n", Color);
5459 glClearColor(D3DCOLOR_R(Color),
5460 D3DCOLOR_G(Color),
5461 D3DCOLOR_B(Color),
5462 D3DCOLOR_A(Color));
5463 checkGLcall("glClearColor");
5465 /* Clear ALL colors! */
5466 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5467 glMask = glMask | GL_COLOR_BUFFER_BIT;
5470 vp_rect.left = vp->X;
5471 vp_rect.top = vp->Y;
5472 vp_rect.right = vp->X + vp->Width;
5473 vp_rect.bottom = vp->Y + vp->Height;
5474 if (!(Count > 0 && pRects)) {
5475 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5476 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5478 if(This->render_offscreen) {
5479 glScissor(vp_rect.left, vp_rect.top,
5480 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5481 } else {
5482 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5483 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5485 checkGLcall("glScissor");
5486 glClear(glMask);
5487 checkGLcall("glClear");
5488 } else {
5489 /* Now process each rect in turn */
5490 for (i = 0; i < Count; i++) {
5491 /* Note gl uses lower left, width/height */
5492 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5493 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5494 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5496 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5497 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5498 curRect.x1, (target->currentDesc.Height - curRect.y2),
5499 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5501 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5502 * The rectangle is not cleared, no error is returned, but further rectanlges are
5503 * still cleared if they are valid
5505 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5506 TRACE("Rectangle with negative dimensions, ignoring\n");
5507 continue;
5510 if(This->render_offscreen) {
5511 glScissor(curRect.x1, curRect.y1,
5512 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5513 } else {
5514 glScissor(curRect.x1, drawable_height - curRect.y2,
5515 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5517 checkGLcall("glScissor");
5519 glClear(glMask);
5520 checkGLcall("glClear");
5524 /* Restore the old values (why..?) */
5525 if (Flags & WINED3DCLEAR_STENCIL) {
5526 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5528 if (Flags & WINED3DCLEAR_TARGET) {
5529 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5530 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5531 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5532 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5533 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5535 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5536 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5538 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5540 if (Flags & WINED3DCLEAR_ZBUFFER) {
5541 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5542 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5543 surface_modify_ds_location(This->stencilBufferTarget, location);
5546 LEAVE_GL();
5548 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5549 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5550 glFlush();
5552 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5555 return WINED3D_OK;
5558 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5559 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5560 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5561 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5563 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5564 Count, pRects, Flags, Color, Z, Stencil);
5566 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5567 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5568 /* TODO: What about depth stencil buffers without stencil bits? */
5569 return WINED3DERR_INVALIDCALL;
5572 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5575 /*****
5576 * Drawing functions
5577 *****/
5579 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
5580 WINED3DPRIMITIVETYPE primitive_type)
5582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5584 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
5586 This->updateStateBlock->changed.primitive_type = TRUE;
5587 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
5590 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
5591 WINED3DPRIMITIVETYPE *primitive_type)
5593 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5595 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
5597 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
5599 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
5602 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
5604 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5606 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
5608 if(!This->stateBlock->vertexDecl) {
5609 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5610 return WINED3DERR_INVALIDCALL;
5613 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5614 if(This->stateBlock->streamIsUP) {
5615 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5616 This->stateBlock->streamIsUP = FALSE;
5619 if(This->stateBlock->loadBaseVertexIndex != 0) {
5620 This->stateBlock->loadBaseVertexIndex = 0;
5621 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5623 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5624 drawPrimitive(iface, vertex_count, 0/* NumVertices */, StartVertex /* start_idx */,
5625 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5626 return WINED3D_OK;
5629 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5630 UINT minIndex, UINT NumVertices, UINT startIndex, UINT index_count)
5632 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5633 UINT idxStride = 2;
5634 IWineD3DBuffer *pIB;
5635 GLuint vbo;
5637 pIB = This->stateBlock->pIndexData;
5638 if (!pIB) {
5639 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5640 * without an index buffer set. (The first time at least...)
5641 * D3D8 simply dies, but I doubt it can do much harm to return
5642 * D3DERR_INVALIDCALL there as well. */
5643 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5644 return WINED3DERR_INVALIDCALL;
5647 if(!This->stateBlock->vertexDecl) {
5648 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5649 return WINED3DERR_INVALIDCALL;
5652 if(This->stateBlock->streamIsUP) {
5653 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5654 This->stateBlock->streamIsUP = FALSE;
5656 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
5658 TRACE("(%p) : min %u, vertex count %u, startIdx %u, index count %u\n",
5659 This, minIndex, NumVertices, startIndex, index_count);
5661 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
5662 idxStride = 2;
5663 } else {
5664 idxStride = 4;
5667 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5668 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5669 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5672 drawPrimitive(iface, index_count, NumVertices, startIndex, idxStride,
5673 vbo ? NULL : ((struct wined3d_buffer *) pIB)->resource.allocatedMemory, minIndex);
5675 return WINED3D_OK;
5678 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
5679 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5681 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5682 IWineD3DBuffer *vb;
5684 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
5685 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
5687 if(!This->stateBlock->vertexDecl) {
5688 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5689 return WINED3DERR_INVALIDCALL;
5692 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5693 vb = This->stateBlock->streamSource[0];
5694 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5695 if (vb) IWineD3DBuffer_Release(vb);
5696 This->stateBlock->streamOffset[0] = 0;
5697 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5698 This->stateBlock->streamIsUP = TRUE;
5699 This->stateBlock->loadBaseVertexIndex = 0;
5701 /* TODO: Only mark dirty if drawing from a different UP address */
5702 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5704 drawPrimitive(iface, vertex_count, 0 /* NumVertices */, 0 /* start_idx */,
5705 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5707 /* MSDN specifies stream zero settings must be set to NULL */
5708 This->stateBlock->streamStride[0] = 0;
5709 This->stateBlock->streamSource[0] = NULL;
5711 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5712 * the new stream sources or use UP drawing again
5714 return WINED3D_OK;
5717 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, UINT MinVertexIndex,
5718 UINT NumVertices, UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
5719 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5721 int idxStride;
5722 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5723 IWineD3DBuffer *vb;
5724 IWineD3DBuffer *ib;
5726 TRACE("(%p) : MinVtxIdx %u, NumVIdx %u, index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u\n",
5727 This, MinVertexIndex, NumVertices, index_count, pIndexData,
5728 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5730 if(!This->stateBlock->vertexDecl) {
5731 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5732 return WINED3DERR_INVALIDCALL;
5735 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
5736 idxStride = 2;
5737 } else {
5738 idxStride = 4;
5741 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5742 vb = This->stateBlock->streamSource[0];
5743 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5744 if (vb) IWineD3DBuffer_Release(vb);
5745 This->stateBlock->streamIsUP = TRUE;
5746 This->stateBlock->streamOffset[0] = 0;
5747 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5749 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5750 This->stateBlock->baseVertexIndex = 0;
5751 This->stateBlock->loadBaseVertexIndex = 0;
5752 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5753 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5754 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5756 drawPrimitive(iface, index_count, NumVertices, 0 /* start_idx */,
5757 idxStride, pIndexData, MinVertexIndex);
5759 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5760 This->stateBlock->streamSource[0] = NULL;
5761 This->stateBlock->streamStride[0] = 0;
5762 ib = This->stateBlock->pIndexData;
5763 if(ib) {
5764 IWineD3DBuffer_Release(ib);
5765 This->stateBlock->pIndexData = NULL;
5767 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5768 * SetStreamSource to specify a vertex buffer
5771 return WINED3D_OK;
5774 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5775 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
5777 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5779 /* Mark the state dirty until we have nicer tracking
5780 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5781 * that value.
5783 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5784 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5785 This->stateBlock->baseVertexIndex = 0;
5786 This->up_strided = DrawPrimStrideData;
5787 drawPrimitive(iface, vertex_count, 0, 0, 0, NULL, 0);
5788 This->up_strided = NULL;
5789 return WINED3D_OK;
5792 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5793 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
5794 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
5796 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5797 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5799 /* Mark the state dirty until we have nicer tracking
5800 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5801 * that value.
5803 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5804 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5805 This->stateBlock->streamIsUP = TRUE;
5806 This->stateBlock->baseVertexIndex = 0;
5807 This->up_strided = DrawPrimStrideData;
5808 drawPrimitive(iface, vertex_count, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData, 0 /* minindex */);
5809 This->up_strided = NULL;
5810 return WINED3D_OK;
5813 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5814 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5815 * not callable by the app directly no parameter validation checks are needed here.
5817 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5818 WINED3DLOCKED_BOX src;
5819 WINED3DLOCKED_BOX dst;
5820 HRESULT hr;
5821 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5823 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5824 * dirtification to improve loading performance.
5826 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5827 if(FAILED(hr)) return hr;
5828 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5829 if(FAILED(hr)) {
5830 IWineD3DVolume_UnlockBox(pSourceVolume);
5831 return hr;
5834 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5836 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5837 if(FAILED(hr)) {
5838 IWineD3DVolume_UnlockBox(pSourceVolume);
5839 } else {
5840 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5842 return hr;
5845 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5846 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5847 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5848 HRESULT hr = WINED3D_OK;
5849 WINED3DRESOURCETYPE sourceType;
5850 WINED3DRESOURCETYPE destinationType;
5851 int i ,levels;
5853 /* TODO: think about moving the code into IWineD3DBaseTexture */
5855 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5857 /* verify that the source and destination textures aren't NULL */
5858 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5859 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5860 This, pSourceTexture, pDestinationTexture);
5861 hr = WINED3DERR_INVALIDCALL;
5864 if (pSourceTexture == pDestinationTexture) {
5865 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5866 This, pSourceTexture, pDestinationTexture);
5867 hr = WINED3DERR_INVALIDCALL;
5869 /* Verify that the source and destination textures are the same type */
5870 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5871 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5873 if (sourceType != destinationType) {
5874 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5875 This);
5876 hr = WINED3DERR_INVALIDCALL;
5879 /* check that both textures have the identical numbers of levels */
5880 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5881 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5882 hr = WINED3DERR_INVALIDCALL;
5885 if (WINED3D_OK == hr) {
5886 IWineD3DBaseTextureImpl *pDestImpl = (IWineD3DBaseTextureImpl *) pDestinationTexture;
5888 /* Make sure that the destination texture is loaded */
5889 pDestImpl->baseTexture.internal_preload(pDestinationTexture, SRGB_RGB);
5891 /* Update every surface level of the texture */
5892 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5894 switch (sourceType) {
5895 case WINED3DRTYPE_TEXTURE:
5897 IWineD3DSurface *srcSurface;
5898 IWineD3DSurface *destSurface;
5900 for (i = 0 ; i < levels ; ++i) {
5901 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5902 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5903 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5904 IWineD3DSurface_Release(srcSurface);
5905 IWineD3DSurface_Release(destSurface);
5906 if (WINED3D_OK != hr) {
5907 WARN("(%p) : Call to update surface failed\n", This);
5908 return hr;
5912 break;
5913 case WINED3DRTYPE_CUBETEXTURE:
5915 IWineD3DSurface *srcSurface;
5916 IWineD3DSurface *destSurface;
5917 WINED3DCUBEMAP_FACES faceType;
5919 for (i = 0 ; i < levels ; ++i) {
5920 /* Update each cube face */
5921 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5922 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5923 if (WINED3D_OK != hr) {
5924 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5925 } else {
5926 TRACE("Got srcSurface %p\n", srcSurface);
5928 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5929 if (WINED3D_OK != hr) {
5930 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5931 } else {
5932 TRACE("Got desrSurface %p\n", destSurface);
5934 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5935 IWineD3DSurface_Release(srcSurface);
5936 IWineD3DSurface_Release(destSurface);
5937 if (WINED3D_OK != hr) {
5938 WARN("(%p) : Call to update surface failed\n", This);
5939 return hr;
5944 break;
5946 case WINED3DRTYPE_VOLUMETEXTURE:
5948 IWineD3DVolume *srcVolume = NULL;
5949 IWineD3DVolume *destVolume = NULL;
5951 for (i = 0 ; i < levels ; ++i) {
5952 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5953 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5954 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5955 IWineD3DVolume_Release(srcVolume);
5956 IWineD3DVolume_Release(destVolume);
5957 if (WINED3D_OK != hr) {
5958 WARN("(%p) : Call to update volume failed\n", This);
5959 return hr;
5963 break;
5965 default:
5966 FIXME("(%p) : Unsupported source and destination type\n", This);
5967 hr = WINED3DERR_INVALIDCALL;
5971 return hr;
5974 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5975 IWineD3DSwapChain *swapChain;
5976 HRESULT hr;
5977 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5978 if(hr == WINED3D_OK) {
5979 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5980 IWineD3DSwapChain_Release(swapChain);
5982 return hr;
5985 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5986 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5987 IWineD3DBaseTextureImpl *texture;
5988 DWORD i;
5990 TRACE("(%p) : %p\n", This, pNumPasses);
5992 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5993 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5994 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5995 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5997 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5998 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5999 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
6002 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
6003 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
6005 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
6006 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
6007 return E_FAIL;
6009 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
6010 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
6011 return E_FAIL;
6013 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
6014 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
6015 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
6016 return E_FAIL;
6020 /* return a sensible default */
6021 *pNumPasses = 1;
6023 TRACE("returning D3D_OK\n");
6024 return WINED3D_OK;
6027 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
6029 int i;
6031 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
6032 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
6033 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8
6034 || texture->resource.format_desc->format == WINED3DFMT_A8P8))
6036 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
6041 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
6042 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6043 int j;
6044 UINT NewSize;
6045 PALETTEENTRY **palettes;
6047 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6049 if (PaletteNumber >= MAX_PALETTES) {
6050 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6051 return WINED3DERR_INVALIDCALL;
6054 if (PaletteNumber >= This->NumberOfPalettes) {
6055 NewSize = This->NumberOfPalettes;
6056 do {
6057 NewSize *= 2;
6058 } while(PaletteNumber >= NewSize);
6059 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
6060 if (!palettes) {
6061 ERR("Out of memory!\n");
6062 return E_OUTOFMEMORY;
6064 This->palettes = palettes;
6065 This->NumberOfPalettes = NewSize;
6068 if (!This->palettes[PaletteNumber]) {
6069 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
6070 if (!This->palettes[PaletteNumber]) {
6071 ERR("Out of memory!\n");
6072 return E_OUTOFMEMORY;
6076 for (j = 0; j < 256; ++j) {
6077 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
6078 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
6079 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
6080 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
6082 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
6083 TRACE("(%p) : returning\n", This);
6084 return WINED3D_OK;
6087 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
6088 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6089 int j;
6090 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6091 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
6092 /* What happens in such situation isn't documented; Native seems to silently abort
6093 on such conditions. Return Invalid Call. */
6094 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
6095 return WINED3DERR_INVALIDCALL;
6097 for (j = 0; j < 256; ++j) {
6098 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
6099 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
6100 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
6101 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
6103 TRACE("(%p) : returning\n", This);
6104 return WINED3D_OK;
6107 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
6108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6109 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6110 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
6111 (tested with reference rasterizer). Return Invalid Call. */
6112 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
6113 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
6114 return WINED3DERR_INVALIDCALL;
6116 /*TODO: stateblocks */
6117 if (This->currentPalette != PaletteNumber) {
6118 This->currentPalette = PaletteNumber;
6119 dirtify_p8_texture_samplers(This);
6121 TRACE("(%p) : returning\n", This);
6122 return WINED3D_OK;
6125 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
6126 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6127 if (PaletteNumber == NULL) {
6128 WARN("(%p) : returning Invalid Call\n", This);
6129 return WINED3DERR_INVALIDCALL;
6131 /*TODO: stateblocks */
6132 *PaletteNumber = This->currentPalette;
6133 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
6134 return WINED3D_OK;
6137 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
6138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6139 static BOOL warned;
6140 if (!warned)
6142 FIXME("(%p) : stub\n", This);
6143 warned = TRUE;
6146 This->softwareVertexProcessing = bSoftware;
6147 return WINED3D_OK;
6151 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
6152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6153 static BOOL warned;
6154 if (!warned)
6156 FIXME("(%p) : stub\n", This);
6157 warned = TRUE;
6159 return This->softwareVertexProcessing;
6163 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
6164 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6165 IWineD3DSwapChain *swapChain;
6166 HRESULT hr;
6168 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
6170 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
6171 if(hr == WINED3D_OK){
6172 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
6173 IWineD3DSwapChain_Release(swapChain);
6174 }else{
6175 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
6177 return hr;
6181 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
6182 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6183 static BOOL warned;
6184 if(nSegments != 0.0f) {
6185 if (!warned)
6187 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
6188 warned = TRUE;
6191 return WINED3D_OK;
6194 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
6195 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6196 static BOOL warned;
6197 if (!warned)
6199 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
6200 warned = TRUE;
6202 return 0.0f;
6205 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
6206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6207 /** TODO: remove casts to IWineD3DSurfaceImpl
6208 * NOTE: move code to surface to accomplish this
6209 ****************************************/
6210 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
6211 int srcWidth, srcHeight;
6212 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
6213 WINED3DFORMAT destFormat, srcFormat;
6214 UINT destSize;
6215 int srcLeft, destLeft, destTop;
6216 WINED3DPOOL srcPool, destPool;
6217 int offset = 0;
6218 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
6219 glDescriptor *glDescription = NULL;
6220 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
6221 GLenum dummy;
6222 int sampler;
6223 int bpp;
6224 CONVERT_TYPES convert = NO_CONVERSION;
6226 WINED3DSURFACE_DESC winedesc;
6228 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
6229 memset(&winedesc, 0, sizeof(winedesc));
6230 winedesc.Width = &srcSurfaceWidth;
6231 winedesc.Height = &srcSurfaceHeight;
6232 winedesc.Pool = &srcPool;
6233 winedesc.Format = &srcFormat;
6235 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6237 winedesc.Width = &destSurfaceWidth;
6238 winedesc.Height = &destSurfaceHeight;
6239 winedesc.Pool = &destPool;
6240 winedesc.Format = &destFormat;
6241 winedesc.Size = &destSize;
6243 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6245 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
6246 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
6247 return WINED3DERR_INVALIDCALL;
6250 /* This call loads the opengl surface directly, instead of copying the surface to the
6251 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
6252 * copy in sysmem and use regular surface loading.
6254 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
6255 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
6256 if(convert != NO_CONVERSION) {
6257 return IWineD3DSurface_BltFast(pDestinationSurface,
6258 pDestPoint ? pDestPoint->x : 0,
6259 pDestPoint ? pDestPoint->y : 0,
6260 pSourceSurface, pSourceRect, 0);
6263 if (destFormat == WINED3DFMT_UNKNOWN) {
6264 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6265 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6267 /* Get the update surface description */
6268 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6271 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6273 ENTER_GL();
6274 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6275 checkGLcall("glActiveTextureARB");
6276 LEAVE_GL();
6278 /* Make sure the surface is loaded and up to date */
6279 surface_internal_preload(pDestinationSurface, SRGB_RGB);
6280 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
6282 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
6284 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
6285 dst_format_desc = ((IWineD3DSurfaceImpl *)pDestinationSurface)->resource.format_desc;
6287 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6288 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6289 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
6290 srcLeft = pSourceRect ? pSourceRect->left : 0;
6291 destLeft = pDestPoint ? pDestPoint->x : 0;
6292 destTop = pDestPoint ? pDestPoint->y : 0;
6295 /* This function doesn't support compressed textures
6296 the pitch is just bytesPerPixel * width */
6297 if(srcWidth != srcSurfaceWidth || srcLeft ){
6298 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
6299 offset += srcLeft * src_format_desc->byte_count;
6300 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6302 /* TODO DXT formats */
6304 if(pSourceRect != NULL && pSourceRect->top != 0){
6305 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
6307 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
6308 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
6309 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
6311 /* Sanity check */
6312 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6314 /* need to lock the surface to get the data */
6315 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6318 ENTER_GL();
6320 /* TODO: Cube and volume support */
6321 if(rowoffset != 0){
6322 /* not a whole row so we have to do it a line at a time */
6323 int j;
6325 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
6326 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6328 for (j = destTop; j < (srcHeight + destTop); ++j)
6330 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, j,
6331 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
6332 data += rowoffset;
6335 } else { /* Full width, so just write out the whole texture */
6336 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6338 if (WINED3DFMT_DXT1 == destFormat ||
6339 WINED3DFMT_DXT2 == destFormat ||
6340 WINED3DFMT_DXT3 == destFormat ||
6341 WINED3DFMT_DXT4 == destFormat ||
6342 WINED3DFMT_DXT5 == destFormat) {
6343 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6344 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6345 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
6346 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6347 } if (destFormat != srcFormat) {
6348 FIXME("Updating mixed format compressed texture is not curretly support\n");
6349 } else {
6350 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
6351 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
6353 } else {
6354 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6358 } else {
6359 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
6360 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
6363 checkGLcall("glTexSubImage2D");
6365 LEAVE_GL();
6367 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
6368 sampler = This->rev_tex_unit_map[0];
6369 if (sampler != -1) {
6370 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6373 return WINED3D_OK;
6376 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6377 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6378 struct WineD3DRectPatch *patch;
6379 GLenum old_primitive_type;
6380 unsigned int i;
6381 struct list *e;
6382 BOOL found;
6383 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6385 if(!(Handle || pRectPatchInfo)) {
6386 /* TODO: Write a test for the return value, thus the FIXME */
6387 FIXME("Both Handle and pRectPatchInfo are NULL\n");
6388 return WINED3DERR_INVALIDCALL;
6391 if(Handle) {
6392 i = PATCHMAP_HASHFUNC(Handle);
6393 found = FALSE;
6394 LIST_FOR_EACH(e, &This->patches[i]) {
6395 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6396 if(patch->Handle == Handle) {
6397 found = TRUE;
6398 break;
6402 if(!found) {
6403 TRACE("Patch does not exist. Creating a new one\n");
6404 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6405 patch->Handle = Handle;
6406 list_add_head(&This->patches[i], &patch->entry);
6407 } else {
6408 TRACE("Found existing patch %p\n", patch);
6410 } else {
6411 /* Since opengl does not load tesselated vertex attributes into numbered vertex
6412 * attributes we have to tesselate, read back, and draw. This needs a patch
6413 * management structure instance. Create one.
6415 * A possible improvement is to check if a vertex shader is used, and if not directly
6416 * draw the patch.
6418 FIXME("Drawing an uncached patch. This is slow\n");
6419 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6422 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
6423 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
6424 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
6425 HRESULT hr;
6426 TRACE("Tesselation density or patch info changed, retesselating\n");
6428 if(pRectPatchInfo) {
6429 patch->RectPatchInfo = *pRectPatchInfo;
6431 patch->numSegs[0] = pNumSegs[0];
6432 patch->numSegs[1] = pNumSegs[1];
6433 patch->numSegs[2] = pNumSegs[2];
6434 patch->numSegs[3] = pNumSegs[3];
6436 hr = tesselate_rectpatch(This, patch);
6437 if(FAILED(hr)) {
6438 WARN("Patch tesselation failed\n");
6440 /* Do not release the handle to store the params of the patch */
6441 if(!Handle) {
6442 HeapFree(GetProcessHeap(), 0, patch);
6444 return hr;
6448 This->currentPatch = patch;
6449 old_primitive_type = This->stateBlock->gl_primitive_type;
6450 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
6451 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
6452 This->stateBlock->gl_primitive_type = old_primitive_type;
6453 This->currentPatch = NULL;
6455 /* Destroy uncached patches */
6456 if(!Handle) {
6457 HeapFree(GetProcessHeap(), 0, patch->mem);
6458 HeapFree(GetProcessHeap(), 0, patch);
6460 return WINED3D_OK;
6463 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6464 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6465 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6466 FIXME("(%p) : Stub\n", This);
6467 return WINED3D_OK;
6470 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6471 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6472 int i;
6473 struct WineD3DRectPatch *patch;
6474 struct list *e;
6475 TRACE("(%p) Handle(%d)\n", This, Handle);
6477 i = PATCHMAP_HASHFUNC(Handle);
6478 LIST_FOR_EACH(e, &This->patches[i]) {
6479 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6480 if(patch->Handle == Handle) {
6481 TRACE("Deleting patch %p\n", patch);
6482 list_remove(&patch->entry);
6483 HeapFree(GetProcessHeap(), 0, patch->mem);
6484 HeapFree(GetProcessHeap(), 0, patch);
6485 return WINED3D_OK;
6489 /* TODO: Write a test for the return value */
6490 FIXME("Attempt to destroy nonexistent patch\n");
6491 return WINED3DERR_INVALIDCALL;
6494 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6495 HRESULT hr;
6496 IWineD3DSwapChain *swapchain;
6498 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6499 if (SUCCEEDED(hr)) {
6500 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6501 return swapchain;
6504 return NULL;
6507 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
6508 const WINED3DRECT *rect, const float color[4])
6510 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6511 IWineD3DSwapChain *swapchain;
6513 swapchain = get_swapchain(surface);
6514 if (swapchain) {
6515 GLenum buffer;
6517 TRACE("Surface %p is onscreen\n", surface);
6519 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6520 ENTER_GL();
6521 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6522 buffer = surface_get_gl_buffer(surface, swapchain);
6523 glDrawBuffer(buffer);
6524 checkGLcall("glDrawBuffer()");
6525 } else {
6526 TRACE("Surface %p is offscreen\n", surface);
6528 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6529 ENTER_GL();
6530 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6531 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6532 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6533 checkGLcall("glFramebufferRenderbufferEXT");
6536 if (rect) {
6537 glEnable(GL_SCISSOR_TEST);
6538 if(!swapchain) {
6539 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6540 } else {
6541 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6542 rect->x2 - rect->x1, rect->y2 - rect->y1);
6544 checkGLcall("glScissor");
6545 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6546 } else {
6547 glDisable(GL_SCISSOR_TEST);
6549 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6551 glDisable(GL_BLEND);
6552 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6554 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6555 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6557 glClearColor(color[0], color[1], color[2], color[3]);
6558 glClear(GL_COLOR_BUFFER_BIT);
6559 checkGLcall("glClear");
6561 if (This->activeContext->current_fbo) {
6562 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6563 } else {
6564 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6565 checkGLcall("glBindFramebuffer()");
6568 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6569 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6570 glDrawBuffer(GL_BACK);
6571 checkGLcall("glDrawBuffer()");
6574 LEAVE_GL();
6577 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6578 unsigned int r, g, b, a;
6579 DWORD ret;
6581 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6582 destfmt == WINED3DFMT_R8G8B8)
6583 return color;
6585 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6587 a = (color & 0xff000000) >> 24;
6588 r = (color & 0x00ff0000) >> 16;
6589 g = (color & 0x0000ff00) >> 8;
6590 b = (color & 0x000000ff) >> 0;
6592 switch(destfmt)
6594 case WINED3DFMT_R5G6B5:
6595 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6596 r = (r * 32) / 256;
6597 g = (g * 64) / 256;
6598 b = (b * 32) / 256;
6599 ret = r << 11;
6600 ret |= g << 5;
6601 ret |= b;
6602 TRACE("Returning %08x\n", ret);
6603 return ret;
6605 case WINED3DFMT_X1R5G5B5:
6606 case WINED3DFMT_A1R5G5B5:
6607 a = (a * 2) / 256;
6608 r = (r * 32) / 256;
6609 g = (g * 32) / 256;
6610 b = (b * 32) / 256;
6611 ret = a << 15;
6612 ret |= r << 10;
6613 ret |= g << 5;
6614 ret |= b << 0;
6615 TRACE("Returning %08x\n", ret);
6616 return ret;
6618 case WINED3DFMT_A8_UNORM:
6619 TRACE("Returning %08x\n", a);
6620 return a;
6622 case WINED3DFMT_X4R4G4B4:
6623 case WINED3DFMT_A4R4G4B4:
6624 a = (a * 16) / 256;
6625 r = (r * 16) / 256;
6626 g = (g * 16) / 256;
6627 b = (b * 16) / 256;
6628 ret = a << 12;
6629 ret |= r << 8;
6630 ret |= g << 4;
6631 ret |= b << 0;
6632 TRACE("Returning %08x\n", ret);
6633 return ret;
6635 case WINED3DFMT_R3G3B2:
6636 r = (r * 8) / 256;
6637 g = (g * 8) / 256;
6638 b = (b * 4) / 256;
6639 ret = r << 5;
6640 ret |= g << 2;
6641 ret |= b << 0;
6642 TRACE("Returning %08x\n", ret);
6643 return ret;
6645 case WINED3DFMT_X8B8G8R8:
6646 case WINED3DFMT_R8G8B8A8_UNORM:
6647 ret = a << 24;
6648 ret |= b << 16;
6649 ret |= g << 8;
6650 ret |= r << 0;
6651 TRACE("Returning %08x\n", ret);
6652 return ret;
6654 case WINED3DFMT_A2R10G10B10:
6655 a = (a * 4) / 256;
6656 r = (r * 1024) / 256;
6657 g = (g * 1024) / 256;
6658 b = (b * 1024) / 256;
6659 ret = a << 30;
6660 ret |= r << 20;
6661 ret |= g << 10;
6662 ret |= b << 0;
6663 TRACE("Returning %08x\n", ret);
6664 return ret;
6666 case WINED3DFMT_R10G10B10A2_UNORM:
6667 a = (a * 4) / 256;
6668 r = (r * 1024) / 256;
6669 g = (g * 1024) / 256;
6670 b = (b * 1024) / 256;
6671 ret = a << 30;
6672 ret |= b << 20;
6673 ret |= g << 10;
6674 ret |= r << 0;
6675 TRACE("Returning %08x\n", ret);
6676 return ret;
6678 default:
6679 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6680 return 0;
6684 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6685 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6686 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6687 WINEDDBLTFX BltFx;
6688 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6690 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6691 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6692 return WINED3DERR_INVALIDCALL;
6695 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6696 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
6697 color_fill_fbo(iface, pSurface, pRect, c);
6698 return WINED3D_OK;
6699 } else {
6700 /* Just forward this to the DirectDraw blitting engine */
6701 memset(&BltFx, 0, sizeof(BltFx));
6702 BltFx.dwSize = sizeof(BltFx);
6703 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
6704 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6705 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6709 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
6710 IWineD3DRendertargetView *rendertarget_view, const float color[4])
6712 IWineD3DResource *resource;
6713 IWineD3DSurface *surface;
6714 HRESULT hr;
6716 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
6717 if (FAILED(hr))
6719 ERR("Failed to get resource, hr %#x\n", hr);
6720 return;
6723 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
6725 FIXME("Only supported on surface resources\n");
6726 IWineD3DResource_Release(resource);
6727 return;
6730 surface = (IWineD3DSurface *)resource;
6732 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6734 color_fill_fbo(iface, surface, NULL, color);
6736 else
6738 WINEDDBLTFX BltFx;
6739 WINED3DCOLOR c;
6741 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
6743 c = ((DWORD)(color[2] * 255.0));
6744 c |= ((DWORD)(color[1] * 255.0)) << 8;
6745 c |= ((DWORD)(color[0] * 255.0)) << 16;
6746 c |= ((DWORD)(color[3] * 255.0)) << 24;
6748 /* Just forward this to the DirectDraw blitting engine */
6749 memset(&BltFx, 0, sizeof(BltFx));
6750 BltFx.dwSize = sizeof(BltFx);
6751 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
6752 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6753 if (FAILED(hr))
6755 ERR("Blt failed, hr %#x\n", hr);
6759 IWineD3DResource_Release(resource);
6762 /* rendertarget and depth stencil functions */
6763 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6766 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6767 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6768 return WINED3DERR_INVALIDCALL;
6771 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6772 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6773 /* Note inc ref on returned surface */
6774 if(*ppRenderTarget != NULL)
6775 IWineD3DSurface_AddRef(*ppRenderTarget);
6776 return WINED3D_OK;
6779 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6780 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6781 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6782 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6783 IWineD3DSwapChainImpl *Swapchain;
6784 HRESULT hr;
6786 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6788 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6789 if(hr != WINED3D_OK) {
6790 ERR("Can't get the swapchain\n");
6791 return hr;
6794 /* Make sure to release the swapchain */
6795 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6797 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6798 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6799 return WINED3DERR_INVALIDCALL;
6801 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6802 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6803 return WINED3DERR_INVALIDCALL;
6806 if(Swapchain->frontBuffer != Front) {
6807 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6809 if(Swapchain->frontBuffer)
6811 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6812 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
6814 Swapchain->frontBuffer = Front;
6816 if(Swapchain->frontBuffer) {
6817 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6818 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
6822 if(Back && !Swapchain->backBuffer) {
6823 /* We need memory for the back buffer array - only one back buffer this way */
6824 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6825 if(!Swapchain->backBuffer) {
6826 ERR("Out of memory\n");
6827 return E_OUTOFMEMORY;
6831 if(Swapchain->backBuffer[0] != Back) {
6832 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6834 /* What to do about the context here in the case of multithreading? Not sure.
6835 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6837 ENTER_GL();
6838 if(!Swapchain->backBuffer[0]) {
6839 /* GL was told to draw to the front buffer at creation,
6840 * undo that
6842 glDrawBuffer(GL_BACK);
6843 checkGLcall("glDrawBuffer(GL_BACK)");
6844 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6845 Swapchain->presentParms.BackBufferCount = 1;
6846 } else if (!Back) {
6847 /* That makes problems - disable for now */
6848 /* glDrawBuffer(GL_FRONT); */
6849 checkGLcall("glDrawBuffer(GL_FRONT)");
6850 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6851 Swapchain->presentParms.BackBufferCount = 0;
6853 LEAVE_GL();
6855 if(Swapchain->backBuffer[0])
6857 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6858 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
6860 Swapchain->backBuffer[0] = Back;
6862 if(Swapchain->backBuffer[0]) {
6863 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6864 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
6865 } else {
6866 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6867 Swapchain->backBuffer = NULL;
6872 return WINED3D_OK;
6875 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6876 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6877 *ppZStencilSurface = This->stencilBufferTarget;
6878 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6880 if(*ppZStencilSurface != NULL) {
6881 /* Note inc ref on returned surface */
6882 IWineD3DSurface_AddRef(*ppZStencilSurface);
6883 return WINED3D_OK;
6884 } else {
6885 return WINED3DERR_NOTFOUND;
6889 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6890 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6893 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6894 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6895 GLenum gl_filter;
6896 POINT offset = {0, 0};
6898 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6899 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6900 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6901 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6903 switch (filter) {
6904 case WINED3DTEXF_LINEAR:
6905 gl_filter = GL_LINEAR;
6906 break;
6908 default:
6909 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6910 case WINED3DTEXF_NONE:
6911 case WINED3DTEXF_POINT:
6912 gl_filter = GL_NEAREST;
6913 break;
6916 /* Attach src surface to src fbo */
6917 src_swapchain = get_swapchain(src_surface);
6918 if (src_swapchain) {
6919 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6921 TRACE("Source surface %p is onscreen\n", src_surface);
6922 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6923 /* Make sure the drawable is up to date. In the offscreen case
6924 * attach_surface_fbo() implicitly takes care of this. */
6925 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6927 if(buffer == GL_FRONT) {
6928 RECT windowsize;
6929 UINT h;
6930 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6931 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6932 h = windowsize.bottom - windowsize.top;
6933 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6934 src_rect->y1 = offset.y + h - src_rect->y1;
6935 src_rect->y2 = offset.y + h - src_rect->y2;
6936 } else {
6937 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6938 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6941 ENTER_GL();
6942 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6943 glReadBuffer(buffer);
6944 checkGLcall("glReadBuffer()");
6945 } else {
6946 TRACE("Source surface %p is offscreen\n", src_surface);
6947 ENTER_GL();
6948 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6949 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6950 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6951 checkGLcall("glReadBuffer()");
6952 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6953 checkGLcall("glFramebufferRenderbufferEXT");
6955 LEAVE_GL();
6957 /* Attach dst surface to dst fbo */
6958 dst_swapchain = get_swapchain(dst_surface);
6959 if (dst_swapchain) {
6960 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6962 TRACE("Destination surface %p is onscreen\n", dst_surface);
6963 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6964 /* Make sure the drawable is up to date. In the offscreen case
6965 * attach_surface_fbo() implicitly takes care of this. */
6966 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6968 if(buffer == GL_FRONT) {
6969 RECT windowsize;
6970 UINT h;
6971 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6972 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6973 h = windowsize.bottom - windowsize.top;
6974 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6975 dst_rect->y1 = offset.y + h - dst_rect->y1;
6976 dst_rect->y2 = offset.y + h - dst_rect->y2;
6977 } else {
6978 /* Screen coords = window coords, surface height = window height */
6979 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6980 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6983 ENTER_GL();
6984 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6985 glDrawBuffer(buffer);
6986 checkGLcall("glDrawBuffer()");
6987 } else {
6988 TRACE("Destination surface %p is offscreen\n", dst_surface);
6990 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6991 if(!src_swapchain) {
6992 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6995 ENTER_GL();
6996 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6997 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6998 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6999 checkGLcall("glDrawBuffer()");
7000 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
7001 checkGLcall("glFramebufferRenderbufferEXT");
7003 glDisable(GL_SCISSOR_TEST);
7004 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
7006 if (flip) {
7007 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
7008 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
7009 checkGLcall("glBlitFramebuffer()");
7010 } else {
7011 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
7012 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
7013 checkGLcall("glBlitFramebuffer()");
7016 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
7018 if (This->activeContext->current_fbo) {
7019 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
7020 } else {
7021 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
7022 checkGLcall("glBindFramebuffer()");
7025 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
7026 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
7027 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
7028 glDrawBuffer(GL_BACK);
7029 checkGLcall("glDrawBuffer()");
7031 LEAVE_GL();
7034 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
7035 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7036 WINED3DVIEWPORT viewport;
7038 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
7040 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
7041 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
7042 This, RenderTargetIndex, GL_LIMITS(buffers));
7043 return WINED3DERR_INVALIDCALL;
7046 /* MSDN says that null disables the render target
7047 but a device must always be associated with a render target
7048 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
7050 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
7051 FIXME("Trying to set render target 0 to NULL\n");
7052 return WINED3DERR_INVALIDCALL;
7054 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
7055 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);
7056 return WINED3DERR_INVALIDCALL;
7059 /* If we are trying to set what we already have, don't bother */
7060 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
7061 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7062 return WINED3D_OK;
7064 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
7065 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
7066 This->render_targets[RenderTargetIndex] = pRenderTarget;
7068 /* Render target 0 is special */
7069 if(RenderTargetIndex == 0) {
7070 /* Finally, reset the viewport as the MSDN states. */
7071 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
7072 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
7073 viewport.X = 0;
7074 viewport.Y = 0;
7075 viewport.MaxZ = 1.0f;
7076 viewport.MinZ = 0.0f;
7077 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
7078 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
7079 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
7081 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
7083 return WINED3D_OK;
7086 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
7087 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7088 HRESULT hr = WINED3D_OK;
7089 IWineD3DSurface *tmp;
7091 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
7093 if (pNewZStencil == This->stencilBufferTarget) {
7094 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7095 } else {
7096 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
7097 * depending on the renter target implementation being used.
7098 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
7099 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7100 * stencil buffer and incur an extra memory overhead
7101 ******************************************************/
7103 if (This->stencilBufferTarget) {
7104 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
7105 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
7106 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
7107 } else {
7108 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
7109 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
7110 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
7114 tmp = This->stencilBufferTarget;
7115 This->stencilBufferTarget = pNewZStencil;
7116 /* should we be calling the parent or the wined3d surface? */
7117 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
7118 if (NULL != tmp) IWineD3DSurface_Release(tmp);
7119 hr = WINED3D_OK;
7121 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
7122 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
7123 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
7124 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
7125 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
7129 return hr;
7132 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
7133 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
7134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7135 /* TODO: the use of Impl is deprecated. */
7136 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
7137 WINED3DLOCKED_RECT lockedRect;
7139 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
7141 /* some basic validation checks */
7142 if(This->cursorTexture) {
7143 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7144 ENTER_GL();
7145 glDeleteTextures(1, &This->cursorTexture);
7146 LEAVE_GL();
7147 This->cursorTexture = 0;
7150 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
7151 This->haveHardwareCursor = TRUE;
7152 else
7153 This->haveHardwareCursor = FALSE;
7155 if(pCursorBitmap) {
7156 WINED3DLOCKED_RECT rect;
7158 /* MSDN: Cursor must be A8R8G8B8 */
7159 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format_desc->format)
7161 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
7162 return WINED3DERR_INVALIDCALL;
7165 /* MSDN: Cursor must be smaller than the display mode */
7166 if(pSur->currentDesc.Width > This->ddraw_width ||
7167 pSur->currentDesc.Height > This->ddraw_height) {
7168 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);
7169 return WINED3DERR_INVALIDCALL;
7172 if (!This->haveHardwareCursor) {
7173 /* TODO: MSDN: Cursor sizes must be a power of 2 */
7175 /* Do not store the surface's pointer because the application may
7176 * release it after setting the cursor image. Windows doesn't
7177 * addref the set surface, so we can't do this either without
7178 * creating circular refcount dependencies. Copy out the gl texture
7179 * instead.
7181 This->cursorWidth = pSur->currentDesc.Width;
7182 This->cursorHeight = pSur->currentDesc.Height;
7183 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
7185 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION);
7186 char *mem, *bits = rect.pBits;
7187 GLint intfmt = glDesc->glInternal;
7188 GLint format = glDesc->glFormat;
7189 GLint type = glDesc->glType;
7190 INT height = This->cursorHeight;
7191 INT width = This->cursorWidth;
7192 INT bpp = glDesc->byte_count;
7193 INT i, sampler;
7195 /* Reformat the texture memory (pitch and width can be
7196 * different) */
7197 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
7198 for(i = 0; i < height; i++)
7199 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
7200 IWineD3DSurface_UnlockRect(pCursorBitmap);
7201 ENTER_GL();
7203 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
7204 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
7205 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
7208 /* Make sure that a proper texture unit is selected */
7209 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
7210 checkGLcall("glActiveTextureARB");
7211 sampler = This->rev_tex_unit_map[0];
7212 if (sampler != -1) {
7213 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
7215 /* Create a new cursor texture */
7216 glGenTextures(1, &This->cursorTexture);
7217 checkGLcall("glGenTextures");
7218 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
7219 checkGLcall("glBindTexture");
7220 /* Copy the bitmap memory into the cursor texture */
7221 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
7222 HeapFree(GetProcessHeap(), 0, mem);
7223 checkGLcall("glTexImage2D");
7225 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
7226 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
7227 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
7230 LEAVE_GL();
7232 else
7234 FIXME("A cursor texture was not returned.\n");
7235 This->cursorTexture = 0;
7238 else
7240 /* Draw a hardware cursor */
7241 ICONINFO cursorInfo;
7242 HCURSOR cursor;
7243 /* Create and clear maskBits because it is not needed for
7244 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
7245 * chunks. */
7246 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
7247 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
7248 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
7249 WINED3DLOCK_NO_DIRTY_UPDATE |
7250 WINED3DLOCK_READONLY
7252 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
7253 pSur->currentDesc.Height);
7255 cursorInfo.fIcon = FALSE;
7256 cursorInfo.xHotspot = XHotSpot;
7257 cursorInfo.yHotspot = YHotSpot;
7258 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
7259 pSur->currentDesc.Height, 1,
7260 1, &maskBits);
7261 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
7262 pSur->currentDesc.Height, 1,
7263 32, lockedRect.pBits);
7264 IWineD3DSurface_UnlockRect(pCursorBitmap);
7265 /* Create our cursor and clean up. */
7266 cursor = CreateIconIndirect(&cursorInfo);
7267 SetCursor(cursor);
7268 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
7269 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
7270 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
7271 This->hardwareCursor = cursor;
7272 HeapFree(GetProcessHeap(), 0, maskBits);
7276 This->xHotSpot = XHotSpot;
7277 This->yHotSpot = YHotSpot;
7278 return WINED3D_OK;
7281 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7282 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7283 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7285 This->xScreenSpace = XScreenSpace;
7286 This->yScreenSpace = YScreenSpace;
7288 return;
7292 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7294 BOOL oldVisible = This->bCursorVisible;
7295 POINT pt;
7297 TRACE("(%p) : visible(%d)\n", This, bShow);
7300 * When ShowCursor is first called it should make the cursor appear at the OS's last
7301 * known cursor position. Because of this, some applications just repetitively call
7302 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
7304 GetCursorPos(&pt);
7305 This->xScreenSpace = pt.x;
7306 This->yScreenSpace = pt.y;
7308 if (This->haveHardwareCursor) {
7309 This->bCursorVisible = bShow;
7310 if (bShow)
7311 SetCursor(This->hardwareCursor);
7312 else
7313 SetCursor(NULL);
7315 else
7317 if (This->cursorTexture)
7318 This->bCursorVisible = bShow;
7321 return oldVisible;
7324 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7325 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7326 IWineD3DResourceImpl *resource;
7327 TRACE("(%p) : state (%u)\n", This, This->state);
7329 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
7330 switch (This->state) {
7331 case WINED3D_OK:
7332 return WINED3D_OK;
7333 case WINED3DERR_DEVICELOST:
7335 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7336 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
7337 return WINED3DERR_DEVICENOTRESET;
7339 return WINED3DERR_DEVICELOST;
7341 case WINED3DERR_DRIVERINTERNALERROR:
7342 return WINED3DERR_DRIVERINTERNALERROR;
7345 /* Unknown state */
7346 return WINED3DERR_DRIVERINTERNALERROR;
7350 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7352 /** FIXME: Resource tracking needs to be done,
7353 * The closes we can do to this is set the priorities of all managed textures low
7354 * and then reset them.
7355 ***********************************************************/
7356 FIXME("(%p) : stub\n", This);
7357 return WINED3D_OK;
7360 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
7362 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
7364 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7365 if(surface->Flags & SFLAG_DIBSECTION) {
7366 /* Release the DC */
7367 SelectObject(surface->hDC, surface->dib.holdbitmap);
7368 DeleteDC(surface->hDC);
7369 /* Release the DIB section */
7370 DeleteObject(surface->dib.DIBsection);
7371 surface->dib.bitmap_data = NULL;
7372 surface->resource.allocatedMemory = NULL;
7373 surface->Flags &= ~SFLAG_DIBSECTION;
7375 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7376 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7377 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
7378 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
7379 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7380 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7381 } else {
7382 surface->pow2Width = surface->pow2Height = 1;
7383 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7384 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7386 surface->glRect.left = 0;
7387 surface->glRect.top = 0;
7388 surface->glRect.right = surface->pow2Width;
7389 surface->glRect.bottom = surface->pow2Height;
7391 if(surface->glDescription.textureName) {
7392 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7393 ENTER_GL();
7394 glDeleteTextures(1, &surface->glDescription.textureName);
7395 LEAVE_GL();
7396 surface->glDescription.textureName = 0;
7397 surface->Flags &= ~SFLAG_CLIENT;
7399 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7400 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7401 surface->Flags |= SFLAG_NONPOW2;
7402 } else {
7403 surface->Flags &= ~SFLAG_NONPOW2;
7405 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7406 surface->resource.allocatedMemory = NULL;
7407 surface->resource.heapMemory = NULL;
7408 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7409 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7410 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7411 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7412 } else {
7413 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7417 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7418 TRACE("Unloading resource %p\n", resource);
7419 IWineD3DResource_UnLoad(resource);
7420 IWineD3DResource_Release(resource);
7421 return S_OK;
7424 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
7426 UINT i, count;
7427 WINED3DDISPLAYMODE m;
7428 HRESULT hr;
7430 /* All Windowed modes are supported, as is leaving the current mode */
7431 if(pp->Windowed) return TRUE;
7432 if(!pp->BackBufferWidth) return TRUE;
7433 if(!pp->BackBufferHeight) return TRUE;
7435 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7436 for(i = 0; i < count; i++) {
7437 memset(&m, 0, sizeof(m));
7438 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7439 if(FAILED(hr)) {
7440 ERR("EnumAdapterModes failed\n");
7442 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7443 /* Mode found, it is supported */
7444 return TRUE;
7447 /* Mode not found -> not supported */
7448 return FALSE;
7451 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7452 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7453 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7454 UINT i;
7455 IWineD3DBaseShaderImpl *shader;
7457 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7458 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7459 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7462 ENTER_GL();
7463 if(This->depth_blt_texture) {
7464 glDeleteTextures(1, &This->depth_blt_texture);
7465 This->depth_blt_texture = 0;
7467 if (This->depth_blt_rb) {
7468 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7469 This->depth_blt_rb = 0;
7470 This->depth_blt_rb_w = 0;
7471 This->depth_blt_rb_h = 0;
7473 LEAVE_GL();
7475 This->blitter->free_private(iface);
7476 This->frag_pipe->free_private(iface);
7477 This->shader_backend->shader_free_private(iface);
7479 ENTER_GL();
7480 for (i = 0; i < GL_LIMITS(textures); i++) {
7481 /* Textures are recreated below */
7482 glDeleteTextures(1, &This->dummyTextureName[i]);
7483 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7484 This->dummyTextureName[i] = 0;
7486 LEAVE_GL();
7488 while(This->numContexts) {
7489 DestroyContext(This, This->contexts[0]);
7491 This->activeContext = NULL;
7492 HeapFree(GetProcessHeap(), 0, swapchain->context);
7493 swapchain->context = NULL;
7494 swapchain->num_contexts = 0;
7497 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7498 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7499 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7500 HRESULT hr;
7501 IWineD3DSurfaceImpl *target;
7503 /* Recreate the primary swapchain's context */
7504 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7505 if(swapchain->backBuffer) {
7506 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7507 } else {
7508 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7510 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7511 &swapchain->presentParms);
7512 swapchain->num_contexts = 1;
7513 This->activeContext = swapchain->context[0];
7515 create_dummy_textures(This);
7517 hr = This->shader_backend->shader_alloc_private(iface);
7518 if(FAILED(hr)) {
7519 ERR("Failed to recreate shader private data\n");
7520 goto err_out;
7522 hr = This->frag_pipe->alloc_private(iface);
7523 if(FAILED(hr)) {
7524 TRACE("Fragment pipeline private data couldn't be allocated\n");
7525 goto err_out;
7527 hr = This->blitter->alloc_private(iface);
7528 if(FAILED(hr)) {
7529 TRACE("Blitter private data couldn't be allocated\n");
7530 goto err_out;
7533 return WINED3D_OK;
7535 err_out:
7536 This->blitter->free_private(iface);
7537 This->frag_pipe->free_private(iface);
7538 This->shader_backend->shader_free_private(iface);
7539 return hr;
7542 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7543 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7544 IWineD3DSwapChainImpl *swapchain;
7545 HRESULT hr;
7546 BOOL DisplayModeChanged = FALSE;
7547 WINED3DDISPLAYMODE mode;
7548 TRACE("(%p)\n", This);
7550 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7551 if(FAILED(hr)) {
7552 ERR("Failed to get the first implicit swapchain\n");
7553 return hr;
7556 if(!is_display_mode_supported(This, pPresentationParameters)) {
7557 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7558 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7559 pPresentationParameters->BackBufferHeight);
7560 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
7561 return WINED3DERR_INVALIDCALL;
7564 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7565 * on an existing gl context, so there's no real need for recreation.
7567 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7569 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7571 TRACE("New params:\n");
7572 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7573 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7574 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7575 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7576 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7577 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7578 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7579 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7580 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7581 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7582 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7583 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7584 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7586 /* No special treatment of these parameters. Just store them */
7587 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7588 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7589 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7590 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7592 /* What to do about these? */
7593 if(pPresentationParameters->BackBufferCount != 0 &&
7594 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7595 ERR("Cannot change the back buffer count yet\n");
7597 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7598 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7599 ERR("Cannot change the back buffer format yet\n");
7601 if(pPresentationParameters->hDeviceWindow != NULL &&
7602 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7603 ERR("Cannot change the device window yet\n");
7605 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7606 HRESULT hrc;
7608 TRACE("Creating the depth stencil buffer\n");
7610 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
7611 This->parent,
7612 pPresentationParameters->BackBufferWidth,
7613 pPresentationParameters->BackBufferHeight,
7614 pPresentationParameters->AutoDepthStencilFormat,
7615 pPresentationParameters->MultiSampleType,
7616 pPresentationParameters->MultiSampleQuality,
7617 FALSE,
7618 &This->auto_depth_stencil_buffer);
7620 if (FAILED(hrc)) {
7621 ERR("Failed to create the depth stencil buffer\n");
7622 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7623 return WINED3DERR_INVALIDCALL;
7627 /* Reset the depth stencil */
7628 if (pPresentationParameters->EnableAutoDepthStencil)
7629 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7630 else
7631 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7633 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7635 if(pPresentationParameters->Windowed) {
7636 mode.Width = swapchain->orig_width;
7637 mode.Height = swapchain->orig_height;
7638 mode.RefreshRate = 0;
7639 mode.Format = swapchain->presentParms.BackBufferFormat;
7640 } else {
7641 mode.Width = pPresentationParameters->BackBufferWidth;
7642 mode.Height = pPresentationParameters->BackBufferHeight;
7643 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7644 mode.Format = swapchain->presentParms.BackBufferFormat;
7647 /* Should Width == 800 && Height == 0 set 800x600? */
7648 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7649 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7650 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7652 UINT i;
7654 if(!pPresentationParameters->Windowed) {
7655 DisplayModeChanged = TRUE;
7657 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7658 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7660 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7661 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7662 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7664 if(This->auto_depth_stencil_buffer) {
7665 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7669 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7670 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7671 DisplayModeChanged) {
7673 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7675 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7676 if(swapchain->presentParms.Windowed) {
7677 /* switch from windowed to fs */
7678 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7679 pPresentationParameters->BackBufferWidth,
7680 pPresentationParameters->BackBufferHeight);
7681 } else {
7682 /* Fullscreen -> fullscreen mode change */
7683 MoveWindow(swapchain->win_handle, 0, 0,
7684 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7685 TRUE);
7687 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7688 /* Fullscreen -> windowed switch */
7689 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7691 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7692 } else if(!pPresentationParameters->Windowed) {
7693 DWORD style = This->style, exStyle = This->exStyle;
7694 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7695 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7696 * Reset to clear up their mess. Guild Wars also loses the device during that.
7698 This->style = 0;
7699 This->exStyle = 0;
7700 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7701 pPresentationParameters->BackBufferWidth,
7702 pPresentationParameters->BackBufferHeight);
7703 This->style = style;
7704 This->exStyle = exStyle;
7707 TRACE("Resetting stateblock\n");
7708 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
7709 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
7711 /* Note: No parent needed for initial internal stateblock */
7712 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
7713 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7714 else TRACE("Created stateblock %p\n", This->stateBlock);
7715 This->updateStateBlock = This->stateBlock;
7716 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
7718 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7719 if(FAILED(hr)) {
7720 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7723 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7724 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7726 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7727 * first use
7729 return hr;
7732 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7733 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7734 /** FIXME: always true at the moment **/
7735 if(!bEnableDialogs) {
7736 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7738 return WINED3D_OK;
7742 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7743 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7744 TRACE("(%p) : pParameters %p\n", This, pParameters);
7746 *pParameters = This->createParms;
7747 return WINED3D_OK;
7750 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7751 IWineD3DSwapChain *swapchain;
7753 TRACE("Relaying to swapchain\n");
7755 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7756 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7757 IWineD3DSwapChain_Release(swapchain);
7759 return;
7762 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7763 IWineD3DSwapChain *swapchain;
7765 TRACE("Relaying to swapchain\n");
7767 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7768 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7769 IWineD3DSwapChain_Release(swapchain);
7771 return;
7775 /** ********************************************************
7776 * Notification functions
7777 ** ********************************************************/
7778 /** This function must be called in the release of a resource when ref == 0,
7779 * the contents of resource must still be correct,
7780 * any handles to other resource held by the caller must be closed
7781 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7782 *****************************************************/
7783 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7784 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7786 TRACE("(%p) : Adding Resource %p\n", This, resource);
7787 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7790 static void IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7791 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7793 TRACE("(%p) : Removing resource %p\n", This, resource);
7795 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7799 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7800 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7801 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7802 int counter;
7804 TRACE("(%p) : resource %p\n", This, resource);
7806 context_resource_released(iface, resource, type);
7808 switch (type) {
7809 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7810 case WINED3DRTYPE_SURFACE: {
7811 unsigned int i;
7813 /* Cleanup any FBO attachments if d3d is enabled */
7814 if(This->d3d_initialized) {
7815 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7816 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7818 TRACE("Last active render target destroyed\n");
7819 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7820 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7821 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7822 * and the lastActiveRenderTarget member shouldn't matter
7824 if(swapchain) {
7825 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7826 TRACE("Activating primary back buffer\n");
7827 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7828 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7829 /* Single buffering environment */
7830 TRACE("Activating primary front buffer\n");
7831 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7832 } else {
7833 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7834 /* Implicit render target destroyed, that means the device is being destroyed
7835 * whatever we set here, it shouldn't matter
7837 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7839 } else {
7840 /* May happen during ddraw uninitialization */
7841 TRACE("Render target set, but swapchain does not exist!\n");
7842 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7846 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7847 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7848 This->render_targets[i] = NULL;
7851 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7852 This->stencilBufferTarget = NULL;
7856 break;
7858 case WINED3DRTYPE_TEXTURE:
7859 case WINED3DRTYPE_CUBETEXTURE:
7860 case WINED3DRTYPE_VOLUMETEXTURE:
7861 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7862 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7863 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7864 This->stateBlock->textures[counter] = NULL;
7866 if (This->updateStateBlock != This->stateBlock ){
7867 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7868 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7869 This->updateStateBlock->textures[counter] = NULL;
7873 break;
7874 case WINED3DRTYPE_VOLUME:
7875 /* TODO: nothing really? */
7876 break;
7877 case WINED3DRTYPE_BUFFER:
7879 int streamNumber;
7880 TRACE("Cleaning up stream pointers\n");
7882 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7883 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7884 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7886 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7887 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7888 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7889 This->updateStateBlock->streamSource[streamNumber] = 0;
7890 /* Set changed flag? */
7893 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) */
7894 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7895 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7896 This->stateBlock->streamSource[streamNumber] = 0;
7901 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7902 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7903 This->updateStateBlock->pIndexData = NULL;
7906 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7907 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7908 This->stateBlock->pIndexData = NULL;
7912 break;
7914 default:
7915 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7916 break;
7920 /* Remove the resource from the resourceStore */
7921 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7923 TRACE("Resource released\n");
7927 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7928 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7929 IWineD3DResourceImpl *resource, *cursor;
7930 HRESULT ret;
7931 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7933 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7934 TRACE("enumerating resource %p\n", resource);
7935 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7936 ret = pCallback((IWineD3DResource *) resource, pData);
7937 if(ret == S_FALSE) {
7938 TRACE("Canceling enumeration\n");
7939 break;
7942 return WINED3D_OK;
7945 /**********************************************************
7946 * IWineD3DDevice VTbl follows
7947 **********************************************************/
7949 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7951 /*** IUnknown methods ***/
7952 IWineD3DDeviceImpl_QueryInterface,
7953 IWineD3DDeviceImpl_AddRef,
7954 IWineD3DDeviceImpl_Release,
7955 /*** IWineD3DDevice methods ***/
7956 IWineD3DDeviceImpl_GetParent,
7957 /*** Creation methods**/
7958 IWineD3DDeviceImpl_CreateBuffer,
7959 IWineD3DDeviceImpl_CreateVertexBuffer,
7960 IWineD3DDeviceImpl_CreateIndexBuffer,
7961 IWineD3DDeviceImpl_CreateStateBlock,
7962 IWineD3DDeviceImpl_CreateSurface,
7963 IWineD3DDeviceImpl_CreateRendertargetView,
7964 IWineD3DDeviceImpl_CreateTexture,
7965 IWineD3DDeviceImpl_CreateVolumeTexture,
7966 IWineD3DDeviceImpl_CreateVolume,
7967 IWineD3DDeviceImpl_CreateCubeTexture,
7968 IWineD3DDeviceImpl_CreateQuery,
7969 IWineD3DDeviceImpl_CreateSwapChain,
7970 IWineD3DDeviceImpl_CreateVertexDeclaration,
7971 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7972 IWineD3DDeviceImpl_CreateVertexShader,
7973 IWineD3DDeviceImpl_CreatePixelShader,
7974 IWineD3DDeviceImpl_CreatePalette,
7975 /*** Odd functions **/
7976 IWineD3DDeviceImpl_Init3D,
7977 IWineD3DDeviceImpl_InitGDI,
7978 IWineD3DDeviceImpl_Uninit3D,
7979 IWineD3DDeviceImpl_UninitGDI,
7980 IWineD3DDeviceImpl_SetMultithreaded,
7981 IWineD3DDeviceImpl_EvictManagedResources,
7982 IWineD3DDeviceImpl_GetAvailableTextureMem,
7983 IWineD3DDeviceImpl_GetBackBuffer,
7984 IWineD3DDeviceImpl_GetCreationParameters,
7985 IWineD3DDeviceImpl_GetDeviceCaps,
7986 IWineD3DDeviceImpl_GetDirect3D,
7987 IWineD3DDeviceImpl_GetDisplayMode,
7988 IWineD3DDeviceImpl_SetDisplayMode,
7989 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7990 IWineD3DDeviceImpl_GetRasterStatus,
7991 IWineD3DDeviceImpl_GetSwapChain,
7992 IWineD3DDeviceImpl_Reset,
7993 IWineD3DDeviceImpl_SetDialogBoxMode,
7994 IWineD3DDeviceImpl_SetCursorProperties,
7995 IWineD3DDeviceImpl_SetCursorPosition,
7996 IWineD3DDeviceImpl_ShowCursor,
7997 IWineD3DDeviceImpl_TestCooperativeLevel,
7998 /*** Getters and setters **/
7999 IWineD3DDeviceImpl_SetClipPlane,
8000 IWineD3DDeviceImpl_GetClipPlane,
8001 IWineD3DDeviceImpl_SetClipStatus,
8002 IWineD3DDeviceImpl_GetClipStatus,
8003 IWineD3DDeviceImpl_SetCurrentTexturePalette,
8004 IWineD3DDeviceImpl_GetCurrentTexturePalette,
8005 IWineD3DDeviceImpl_SetDepthStencilSurface,
8006 IWineD3DDeviceImpl_GetDepthStencilSurface,
8007 IWineD3DDeviceImpl_SetGammaRamp,
8008 IWineD3DDeviceImpl_GetGammaRamp,
8009 IWineD3DDeviceImpl_SetIndices,
8010 IWineD3DDeviceImpl_GetIndices,
8011 IWineD3DDeviceImpl_SetBaseVertexIndex,
8012 IWineD3DDeviceImpl_GetBaseVertexIndex,
8013 IWineD3DDeviceImpl_SetLight,
8014 IWineD3DDeviceImpl_GetLight,
8015 IWineD3DDeviceImpl_SetLightEnable,
8016 IWineD3DDeviceImpl_GetLightEnable,
8017 IWineD3DDeviceImpl_SetMaterial,
8018 IWineD3DDeviceImpl_GetMaterial,
8019 IWineD3DDeviceImpl_SetNPatchMode,
8020 IWineD3DDeviceImpl_GetNPatchMode,
8021 IWineD3DDeviceImpl_SetPaletteEntries,
8022 IWineD3DDeviceImpl_GetPaletteEntries,
8023 IWineD3DDeviceImpl_SetPixelShader,
8024 IWineD3DDeviceImpl_GetPixelShader,
8025 IWineD3DDeviceImpl_SetPixelShaderConstantB,
8026 IWineD3DDeviceImpl_GetPixelShaderConstantB,
8027 IWineD3DDeviceImpl_SetPixelShaderConstantI,
8028 IWineD3DDeviceImpl_GetPixelShaderConstantI,
8029 IWineD3DDeviceImpl_SetPixelShaderConstantF,
8030 IWineD3DDeviceImpl_GetPixelShaderConstantF,
8031 IWineD3DDeviceImpl_SetRenderState,
8032 IWineD3DDeviceImpl_GetRenderState,
8033 IWineD3DDeviceImpl_SetRenderTarget,
8034 IWineD3DDeviceImpl_GetRenderTarget,
8035 IWineD3DDeviceImpl_SetFrontBackBuffers,
8036 IWineD3DDeviceImpl_SetSamplerState,
8037 IWineD3DDeviceImpl_GetSamplerState,
8038 IWineD3DDeviceImpl_SetScissorRect,
8039 IWineD3DDeviceImpl_GetScissorRect,
8040 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
8041 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
8042 IWineD3DDeviceImpl_SetStreamSource,
8043 IWineD3DDeviceImpl_GetStreamSource,
8044 IWineD3DDeviceImpl_SetStreamSourceFreq,
8045 IWineD3DDeviceImpl_GetStreamSourceFreq,
8046 IWineD3DDeviceImpl_SetTexture,
8047 IWineD3DDeviceImpl_GetTexture,
8048 IWineD3DDeviceImpl_SetTextureStageState,
8049 IWineD3DDeviceImpl_GetTextureStageState,
8050 IWineD3DDeviceImpl_SetTransform,
8051 IWineD3DDeviceImpl_GetTransform,
8052 IWineD3DDeviceImpl_SetVertexDeclaration,
8053 IWineD3DDeviceImpl_GetVertexDeclaration,
8054 IWineD3DDeviceImpl_SetVertexShader,
8055 IWineD3DDeviceImpl_GetVertexShader,
8056 IWineD3DDeviceImpl_SetVertexShaderConstantB,
8057 IWineD3DDeviceImpl_GetVertexShaderConstantB,
8058 IWineD3DDeviceImpl_SetVertexShaderConstantI,
8059 IWineD3DDeviceImpl_GetVertexShaderConstantI,
8060 IWineD3DDeviceImpl_SetVertexShaderConstantF,
8061 IWineD3DDeviceImpl_GetVertexShaderConstantF,
8062 IWineD3DDeviceImpl_SetViewport,
8063 IWineD3DDeviceImpl_GetViewport,
8064 IWineD3DDeviceImpl_MultiplyTransform,
8065 IWineD3DDeviceImpl_ValidateDevice,
8066 IWineD3DDeviceImpl_ProcessVertices,
8067 /*** State block ***/
8068 IWineD3DDeviceImpl_BeginStateBlock,
8069 IWineD3DDeviceImpl_EndStateBlock,
8070 /*** Scene management ***/
8071 IWineD3DDeviceImpl_BeginScene,
8072 IWineD3DDeviceImpl_EndScene,
8073 IWineD3DDeviceImpl_Present,
8074 IWineD3DDeviceImpl_Clear,
8075 IWineD3DDeviceImpl_ClearRendertargetView,
8076 /*** Drawing ***/
8077 IWineD3DDeviceImpl_SetPrimitiveType,
8078 IWineD3DDeviceImpl_GetPrimitiveType,
8079 IWineD3DDeviceImpl_DrawPrimitive,
8080 IWineD3DDeviceImpl_DrawIndexedPrimitive,
8081 IWineD3DDeviceImpl_DrawPrimitiveUP,
8082 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
8083 IWineD3DDeviceImpl_DrawPrimitiveStrided,
8084 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
8085 IWineD3DDeviceImpl_DrawRectPatch,
8086 IWineD3DDeviceImpl_DrawTriPatch,
8087 IWineD3DDeviceImpl_DeletePatch,
8088 IWineD3DDeviceImpl_ColorFill,
8089 IWineD3DDeviceImpl_UpdateTexture,
8090 IWineD3DDeviceImpl_UpdateSurface,
8091 IWineD3DDeviceImpl_GetFrontBufferData,
8092 /*** object tracking ***/
8093 IWineD3DDeviceImpl_ResourceReleased,
8094 IWineD3DDeviceImpl_EnumResources
8097 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
8098 WINED3DRS_ALPHABLENDENABLE ,
8099 WINED3DRS_ALPHAFUNC ,
8100 WINED3DRS_ALPHAREF ,
8101 WINED3DRS_ALPHATESTENABLE ,
8102 WINED3DRS_BLENDOP ,
8103 WINED3DRS_COLORWRITEENABLE ,
8104 WINED3DRS_DESTBLEND ,
8105 WINED3DRS_DITHERENABLE ,
8106 WINED3DRS_FILLMODE ,
8107 WINED3DRS_FOGDENSITY ,
8108 WINED3DRS_FOGEND ,
8109 WINED3DRS_FOGSTART ,
8110 WINED3DRS_LASTPIXEL ,
8111 WINED3DRS_SHADEMODE ,
8112 WINED3DRS_SRCBLEND ,
8113 WINED3DRS_STENCILENABLE ,
8114 WINED3DRS_STENCILFAIL ,
8115 WINED3DRS_STENCILFUNC ,
8116 WINED3DRS_STENCILMASK ,
8117 WINED3DRS_STENCILPASS ,
8118 WINED3DRS_STENCILREF ,
8119 WINED3DRS_STENCILWRITEMASK ,
8120 WINED3DRS_STENCILZFAIL ,
8121 WINED3DRS_TEXTUREFACTOR ,
8122 WINED3DRS_WRAP0 ,
8123 WINED3DRS_WRAP1 ,
8124 WINED3DRS_WRAP2 ,
8125 WINED3DRS_WRAP3 ,
8126 WINED3DRS_WRAP4 ,
8127 WINED3DRS_WRAP5 ,
8128 WINED3DRS_WRAP6 ,
8129 WINED3DRS_WRAP7 ,
8130 WINED3DRS_ZENABLE ,
8131 WINED3DRS_ZFUNC ,
8132 WINED3DRS_ZWRITEENABLE
8135 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
8136 WINED3DTSS_ALPHAARG0 ,
8137 WINED3DTSS_ALPHAARG1 ,
8138 WINED3DTSS_ALPHAARG2 ,
8139 WINED3DTSS_ALPHAOP ,
8140 WINED3DTSS_BUMPENVLOFFSET ,
8141 WINED3DTSS_BUMPENVLSCALE ,
8142 WINED3DTSS_BUMPENVMAT00 ,
8143 WINED3DTSS_BUMPENVMAT01 ,
8144 WINED3DTSS_BUMPENVMAT10 ,
8145 WINED3DTSS_BUMPENVMAT11 ,
8146 WINED3DTSS_COLORARG0 ,
8147 WINED3DTSS_COLORARG1 ,
8148 WINED3DTSS_COLORARG2 ,
8149 WINED3DTSS_COLOROP ,
8150 WINED3DTSS_RESULTARG ,
8151 WINED3DTSS_TEXCOORDINDEX ,
8152 WINED3DTSS_TEXTURETRANSFORMFLAGS
8155 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
8156 WINED3DSAMP_ADDRESSU ,
8157 WINED3DSAMP_ADDRESSV ,
8158 WINED3DSAMP_ADDRESSW ,
8159 WINED3DSAMP_BORDERCOLOR ,
8160 WINED3DSAMP_MAGFILTER ,
8161 WINED3DSAMP_MINFILTER ,
8162 WINED3DSAMP_MIPFILTER ,
8163 WINED3DSAMP_MIPMAPLODBIAS ,
8164 WINED3DSAMP_MAXMIPLEVEL ,
8165 WINED3DSAMP_MAXANISOTROPY ,
8166 WINED3DSAMP_SRGBTEXTURE ,
8167 WINED3DSAMP_ELEMENTINDEX
8170 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
8171 WINED3DRS_AMBIENT ,
8172 WINED3DRS_AMBIENTMATERIALSOURCE ,
8173 WINED3DRS_CLIPPING ,
8174 WINED3DRS_CLIPPLANEENABLE ,
8175 WINED3DRS_COLORVERTEX ,
8176 WINED3DRS_DIFFUSEMATERIALSOURCE ,
8177 WINED3DRS_EMISSIVEMATERIALSOURCE ,
8178 WINED3DRS_FOGDENSITY ,
8179 WINED3DRS_FOGEND ,
8180 WINED3DRS_FOGSTART ,
8181 WINED3DRS_FOGTABLEMODE ,
8182 WINED3DRS_FOGVERTEXMODE ,
8183 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
8184 WINED3DRS_LIGHTING ,
8185 WINED3DRS_LOCALVIEWER ,
8186 WINED3DRS_MULTISAMPLEANTIALIAS ,
8187 WINED3DRS_MULTISAMPLEMASK ,
8188 WINED3DRS_NORMALIZENORMALS ,
8189 WINED3DRS_PATCHEDGESTYLE ,
8190 WINED3DRS_POINTSCALE_A ,
8191 WINED3DRS_POINTSCALE_B ,
8192 WINED3DRS_POINTSCALE_C ,
8193 WINED3DRS_POINTSCALEENABLE ,
8194 WINED3DRS_POINTSIZE ,
8195 WINED3DRS_POINTSIZE_MAX ,
8196 WINED3DRS_POINTSIZE_MIN ,
8197 WINED3DRS_POINTSPRITEENABLE ,
8198 WINED3DRS_RANGEFOGENABLE ,
8199 WINED3DRS_SPECULARMATERIALSOURCE ,
8200 WINED3DRS_TWEENFACTOR ,
8201 WINED3DRS_VERTEXBLEND ,
8202 WINED3DRS_CULLMODE ,
8203 WINED3DRS_FOGCOLOR
8206 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8207 WINED3DTSS_TEXCOORDINDEX ,
8208 WINED3DTSS_TEXTURETRANSFORMFLAGS
8211 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8212 WINED3DSAMP_DMAPOFFSET
8215 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
8216 DWORD rep = This->StateTable[state].representative;
8217 DWORD idx;
8218 BYTE shift;
8219 UINT i;
8220 WineD3DContext *context;
8222 if(!rep) return;
8223 for(i = 0; i < This->numContexts; i++) {
8224 context = This->contexts[i];
8225 if(isStateDirty(context, rep)) continue;
8227 context->dirtyArray[context->numDirtyEntries++] = rep;
8228 idx = rep >> 5;
8229 shift = rep & 0x1f;
8230 context->isStateDirty[idx] |= (1 << shift);
8234 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8235 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8236 /* The drawable size of a pbuffer render target is the current pbuffer size
8238 *width = dev->pbufferWidth;
8239 *height = dev->pbufferHeight;
8242 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8243 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
8245 *width = This->pow2Width;
8246 *height = This->pow2Height;
8249 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8250 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8251 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
8252 * current context's drawable, which is the size of the back buffer of the swapchain
8253 * the active context belongs to. The back buffer of the swapchain is stored as the
8254 * surface the context belongs to.
8256 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
8257 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;