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
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 */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
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:
71 case WINED3DPT_LINELIST:
74 case WINED3DPT_LINESTRIP:
77 case WINED3DPT_TRIANGLELIST:
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;
99 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
104 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
106 switch(primitive_type)
109 return WINED3DPT_POINTLIST;
112 return WINED3DPT_LINELIST;
115 return WINED3DPT_LINESTRIP;
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;
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;
164 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
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;
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;
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]);
207 data = (BYTE *)This->stateBlock->streamSource[element->input_slot];
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);
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");
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;
240 /* This may be bad with the fixed function pipeline. */
241 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
247 data += element->offset;
249 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
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);
263 idx = element->output_slot;
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));
277 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
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
308 * NULL streams won't be recorded in the array, UP streams won't be either. A stream is only
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;
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)
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);
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);
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);
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);
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);
439 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface,
440 struct wined3d_buffer_desc *desc, const void *data, IUnknown *parent, IWineD3DBuffer **buffer)
442 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
443 struct wined3d_buffer *object;
446 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
448 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
451 ERR("Failed to allocate memory\n");
452 return E_OUTOFMEMORY;
455 object->vtbl = &wined3d_buffer_vtbl;
456 object->desc = *desc;
458 FIXME("Ignoring access flags (pool)\n");
460 hr = resource_init(&object->resource, WINED3DRTYPE_BUFFER, This, desc->byte_width,
461 desc->usage, WINED3DFMT_UNKNOWN, WINED3DPOOL_MANAGED, parent);
464 WARN("Failed to initialize resource, returning %#x\n", hr);
465 HeapFree(GetProcessHeap(), 0, object);
468 object->buffer_type_hint = GL_ARRAY_BUFFER_ARB;
470 TRACE("Created resource %p\n", object);
472 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
474 TRACE("size %#x, usage=%#x, format %s, memory @ %p, iface @ %p\n", object->resource.size, object->resource.usage,
475 debug_d3dformat(object->resource.format_desc->format), object->resource.allocatedMemory, object);
481 hr = IWineD3DBuffer_Map((IWineD3DBuffer *)object, 0, desc->byte_width, &ptr, 0);
484 ERR("Failed to map buffer, hr %#x\n", hr);
485 IWineD3DBuffer_Release((IWineD3DBuffer *)object);
489 memcpy(ptr, data, desc->byte_width);
491 hr = IWineD3DBuffer_Unmap((IWineD3DBuffer *)object);
494 ERR("Failed to unmap buffer, hr %#x\n", hr);
495 IWineD3DBuffer_Release((IWineD3DBuffer *)object);
500 *buffer = (IWineD3DBuffer *)object;
505 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
506 DWORD FVF, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer, IUnknown *parent)
508 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
509 /* Dummy format for now */
510 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(WINED3DFMT_VERTEXDATA, &This->adapter->gl_info);
511 struct wined3d_buffer *object;
512 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
517 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
518 *ppVertexBuffer = NULL;
519 return WINED3DERR_INVALIDCALL;
520 } else if(Pool == WINED3DPOOL_SCRATCH) {
521 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
522 * anyway, SCRATCH vertex buffers aren't usable anywhere
524 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
525 *ppVertexBuffer = NULL;
526 return WINED3DERR_INVALIDCALL;
529 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
532 ERR("Out of memory\n");
533 *ppVertexBuffer = NULL;
534 return WINED3DERR_OUTOFVIDEOMEMORY;
537 object->vtbl = &wined3d_buffer_vtbl;
538 hr = resource_init(&object->resource, WINED3DRTYPE_BUFFER, This, Size, Usage, format_desc, Pool, parent);
541 WARN("Failed to initialize resource, returning %#x\n", hr);
542 HeapFree(GetProcessHeap(), 0, object);
543 *ppVertexBuffer = NULL;
546 object->buffer_type_hint = GL_ARRAY_BUFFER_ARB;
548 TRACE("(%p) : Created resource %p\n", This, object);
550 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
552 TRACE("(%p) : Size=%d, Usage=0x%08x, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
553 *ppVertexBuffer = (IWineD3DBuffer *)object;
555 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
556 * drawStridedFast (half-life 2).
558 * Basically converting the vertices in the buffer is quite expensive, and observations
559 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
560 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
562 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
563 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
564 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
565 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
567 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
568 * more. In this call we can convert dx7 buffers too.
570 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
571 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
572 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
573 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
574 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
575 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
576 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
577 } else if(dxVersion <= 7 && conv) {
578 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
580 object->flags |= WINED3D_BUFFER_CREATEBO;
585 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
586 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer, IUnknown *parent)
588 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
589 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(WINED3DFMT_UNKNOWN, &This->adapter->gl_info);
590 struct wined3d_buffer *object;
593 TRACE("(%p) Creating index buffer\n", This);
595 /* Allocate the storage for the device */
596 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
599 ERR("Out of memory\n");
600 *ppIndexBuffer = NULL;
601 return WINED3DERR_OUTOFVIDEOMEMORY;
604 object->vtbl = &wined3d_buffer_vtbl;
605 hr = resource_init(&object->resource, WINED3DRTYPE_BUFFER, This, Length, Usage, format_desc, Pool, parent);
608 WARN("Failed to initialize resource, returning %#x\n", hr);
609 HeapFree(GetProcessHeap(), 0, object);
610 *ppIndexBuffer = NULL;
613 object->buffer_type_hint = GL_ELEMENT_ARRAY_BUFFER_ARB;
615 TRACE("(%p) : Created resource %p\n", This, object);
617 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
619 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
620 object->flags |= WINED3D_BUFFER_CREATEBO;
623 TRACE("(%p) : Len=%d, Use=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage,
624 Pool, object, object->resource.allocatedMemory);
625 *ppIndexBuffer = (IWineD3DBuffer *) object;
630 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
632 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
633 IWineD3DStateBlockImpl *object;
637 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
640 ERR("Out of memory\n");
641 *ppStateBlock = NULL;
642 return WINED3DERR_OUTOFVIDEOMEMORY;
645 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
646 object->wineD3DDevice = This;
647 object->parent = parent;
649 object->blockType = Type;
651 *ppStateBlock = (IWineD3DStateBlock *)object;
653 for(i = 0; i < LIGHTMAP_SIZE; i++) {
654 list_init(&object->lightMap[i]);
657 temp_result = allocate_shader_constants(object);
658 if (FAILED(temp_result))
660 HeapFree(GetProcessHeap(), 0, object);
664 /* Special case - Used during initialization to produce a placeholder stateblock
665 so other functions called can update a state block */
666 if (Type == WINED3DSBT_INIT || Type == WINED3DSBT_RECORDED)
668 /* Don't bother increasing the reference count otherwise a device will never
669 be freed due to circular dependencies */
673 /* Otherwise, might as well set the whole state block to the appropriate values */
674 if (This->stateBlock != NULL)
675 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
677 memset(object->streamFreq, 1, sizeof(object->streamFreq));
679 /* Reset the ref and type after kludging it */
680 object->wineD3DDevice = This;
682 object->blockType = Type;
684 TRACE("Updating changed flags appropriate for type %d\n", Type);
686 if (Type == WINED3DSBT_ALL) {
688 TRACE("ALL => Pretend everything has changed\n");
689 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
691 /* Lights are not part of the changed / set structure */
692 for(j = 0; j < LIGHTMAP_SIZE; j++) {
694 LIST_FOR_EACH(e, &object->lightMap[j]) {
695 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
696 light->changed = TRUE;
697 light->enabledChanged = TRUE;
700 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
701 object->contained_render_states[j - 1] = j;
703 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
704 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
705 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
706 object->contained_transform_states[j - 1] = j;
708 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
709 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
710 object->contained_vs_consts_f[j] = j;
712 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
713 for(j = 0; j < MAX_CONST_I; j++) {
714 object->contained_vs_consts_i[j] = j;
716 object->num_contained_vs_consts_i = MAX_CONST_I;
717 for(j = 0; j < MAX_CONST_B; j++) {
718 object->contained_vs_consts_b[j] = j;
720 object->num_contained_vs_consts_b = MAX_CONST_B;
721 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
722 object->contained_ps_consts_f[j] = j;
724 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
725 for(j = 0; j < MAX_CONST_I; j++) {
726 object->contained_ps_consts_i[j] = j;
728 object->num_contained_ps_consts_i = MAX_CONST_I;
729 for(j = 0; j < MAX_CONST_B; j++) {
730 object->contained_ps_consts_b[j] = j;
732 object->num_contained_ps_consts_b = MAX_CONST_B;
733 for(i = 0; i < MAX_TEXTURES; i++) {
734 for (j = 0; j <= WINED3D_HIGHEST_TEXTURE_STATE; ++j)
736 object->contained_tss_states[object->num_contained_tss_states].stage = i;
737 object->contained_tss_states[object->num_contained_tss_states].state = j;
738 object->num_contained_tss_states++;
741 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
742 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
743 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
744 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
745 object->num_contained_sampler_states++;
749 for(i = 0; i < MAX_STREAMS; i++) {
750 if(object->streamSource[i]) {
751 IWineD3DBuffer_AddRef(object->streamSource[i]);
754 if(object->pIndexData) {
755 IWineD3DBuffer_AddRef(object->pIndexData);
757 if(object->vertexShader) {
758 IWineD3DVertexShader_AddRef(object->vertexShader);
760 if(object->pixelShader) {
761 IWineD3DPixelShader_AddRef(object->pixelShader);
764 } else if (Type == WINED3DSBT_PIXELSTATE) {
766 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
767 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
769 object->changed.pixelShader = TRUE;
771 /* Pixel Shader Constants */
772 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
773 object->contained_ps_consts_f[i] = i;
774 object->changed.pixelShaderConstantsF[i] = TRUE;
776 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
777 for (i = 0; i < MAX_CONST_B; ++i) {
778 object->contained_ps_consts_b[i] = i;
779 object->changed.pixelShaderConstantsB |= (1 << i);
781 object->num_contained_ps_consts_b = MAX_CONST_B;
782 for (i = 0; i < MAX_CONST_I; ++i) {
783 object->contained_ps_consts_i[i] = i;
784 object->changed.pixelShaderConstantsI |= (1 << i);
786 object->num_contained_ps_consts_i = MAX_CONST_I;
788 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
789 DWORD rs = SavedPixelStates_R[i];
790 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
791 object->contained_render_states[i] = rs;
793 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
794 for (j = 0; j < MAX_TEXTURES; j++) {
795 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
796 DWORD state = SavedPixelStates_T[i];
797 object->changed.textureState[j] |= 1 << state;
798 object->contained_tss_states[object->num_contained_tss_states].stage = j;
799 object->contained_tss_states[object->num_contained_tss_states].state = state;
800 object->num_contained_tss_states++;
803 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
804 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
805 DWORD state = SavedPixelStates_S[i];
806 object->changed.samplerState[j] |= 1 << state;
807 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
808 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
809 object->num_contained_sampler_states++;
812 if(object->pixelShader) {
813 IWineD3DPixelShader_AddRef(object->pixelShader);
816 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
817 * on them. This makes releasing the buffer easier
819 for(i = 0; i < MAX_STREAMS; i++) {
820 object->streamSource[i] = NULL;
822 object->pIndexData = NULL;
823 object->vertexShader = NULL;
825 } else if (Type == WINED3DSBT_VERTEXSTATE) {
827 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
828 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
830 object->changed.vertexShader = TRUE;
832 /* Vertex Shader Constants */
833 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
834 object->changed.vertexShaderConstantsF[i] = TRUE;
835 object->contained_vs_consts_f[i] = i;
837 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
838 for (i = 0; i < MAX_CONST_B; ++i) {
839 object->contained_vs_consts_b[i] = i;
840 object->changed.vertexShaderConstantsB |= (1 << i);
842 object->num_contained_vs_consts_b = MAX_CONST_B;
843 for (i = 0; i < MAX_CONST_I; ++i) {
844 object->contained_vs_consts_i[i] = i;
845 object->changed.vertexShaderConstantsI |= (1 << i);
847 object->num_contained_vs_consts_i = MAX_CONST_I;
848 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
849 DWORD rs = SavedVertexStates_R[i];
850 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
851 object->contained_render_states[i] = rs;
853 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
854 for (j = 0; j < MAX_TEXTURES; j++) {
855 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
856 DWORD state = SavedVertexStates_T[i];
857 object->changed.textureState[j] |= 1 << state;
858 object->contained_tss_states[object->num_contained_tss_states].stage = j;
859 object->contained_tss_states[object->num_contained_tss_states].state = state;
860 object->num_contained_tss_states++;
863 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
864 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
865 DWORD state = SavedVertexStates_S[i];
866 object->changed.samplerState[j] |= 1 << state;
867 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
868 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
869 object->num_contained_sampler_states++;
873 for(j = 0; j < LIGHTMAP_SIZE; j++) {
875 LIST_FOR_EACH(e, &object->lightMap[j]) {
876 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
877 light->changed = TRUE;
878 light->enabledChanged = TRUE;
882 for(i = 0; i < MAX_STREAMS; i++) {
883 if(object->streamSource[i]) {
884 IWineD3DBuffer_AddRef(object->streamSource[i]);
887 if(object->vertexShader) {
888 IWineD3DVertexShader_AddRef(object->vertexShader);
890 object->pIndexData = NULL;
891 object->pixelShader = NULL;
893 FIXME("Unrecognized state block type %d\n", Type);
896 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
900 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface,
901 UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level,
902 IWineD3DSurface **ppSurface, WINED3DRESOURCETYPE Type, DWORD Usage, WINED3DPOOL Pool,
903 WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, WINED3DSURFTYPE Impl, IUnknown *parent)
905 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
906 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
907 unsigned int Size = 1;
908 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(Format, &GLINFO_LOCATION);
912 TRACE("(%p) Create surface\n",This);
914 if(MultisampleQuality > 0) {
915 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
916 MultisampleQuality=0;
919 /** FIXME: Check that the format is supported
921 *******************************/
923 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
924 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
926 *********************************/
927 mul_4w = (Width + 3) & ~3;
928 mul_4h = (Height + 3) & ~3;
929 if (WINED3DFMT_UNKNOWN == Format) {
931 } else if (Format == WINED3DFMT_DXT1) {
932 /* DXT1 is half byte per pixel */
933 Size = (mul_4w * glDesc->byte_count * mul_4h) >> 1;
935 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
936 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
937 Format == WINED3DFMT_ATI2N) {
938 Size = (mul_4w * glDesc->byte_count * mul_4h);
940 /* The pitch is a multiple of 4 bytes */
941 Size = ((Width * glDesc->byte_count) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
945 if(glDesc->heightscale != 0.0) Size *= glDesc->heightscale;
947 /** Create and initialise the surface resource **/
948 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
951 ERR("Out of memory\n");
953 return WINED3DERR_OUTOFVIDEOMEMORY;
956 /* Look at the implementation and set the correct Vtable */
960 /* Check if a 3D adapter is available when creating gl surfaces */
963 ERR("OpenGL surfaces are not available without opengl\n");
964 HeapFree(GetProcessHeap(), 0, object);
965 return WINED3DERR_NOTAVAILABLE;
967 object->lpVtbl = &IWineD3DSurface_Vtbl;
971 object->lpVtbl = &IWineGDISurface_Vtbl;
975 /* To be sure to catch this */
976 ERR("Unknown requested surface implementation %d!\n", Impl);
977 HeapFree(GetProcessHeap(), 0, object);
978 return WINED3DERR_INVALIDCALL;
981 hr = resource_init(&object->resource, WINED3DRTYPE_SURFACE, This, Size, Usage, glDesc, Pool, parent);
984 WARN("Failed to initialize resource, returning %#x\n", hr);
985 HeapFree(GetProcessHeap(), 0, object);
990 TRACE("(%p) : Created resource %p\n", This, object);
992 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
994 *ppSurface = (IWineD3DSurface *)object;
996 /* "Standalone" surface */
997 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
999 object->currentDesc.Width = Width;
1000 object->currentDesc.Height = Height;
1001 object->currentDesc.MultiSampleType = MultiSample;
1002 object->currentDesc.MultiSampleQuality = MultisampleQuality;
1003 object->glDescription.level = Level;
1004 list_init(&object->overlays);
1007 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
1008 object->Flags |= Discard ? SFLAG_DISCARD : 0;
1009 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
1010 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
1012 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
1014 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
1015 * this function is too deep to need to care about things like this.
1016 * Levels need to be checked too, and possibly Type since they all affect what can be done.
1017 * ****************************************/
1019 case WINED3DPOOL_SCRATCH:
1021 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
1022 "which are mutually exclusive, setting lockable to TRUE\n");
1025 case WINED3DPOOL_SYSTEMMEM:
1026 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
1027 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
1028 case WINED3DPOOL_MANAGED:
1029 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
1030 "Usage of DYNAMIC which are mutually exclusive, not doing "
1031 "anything just telling you.\n");
1033 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
1034 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
1035 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
1036 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
1039 FIXME("(%p) Unknown pool %d\n", This, Pool);
1043 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
1044 FIXME("Trying to create a render target that isn't in the default pool\n");
1047 /* mark the texture as dirty so that it gets loaded first time around*/
1048 surface_add_dirty_rect(*ppSurface, NULL);
1049 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
1050 This, Width, Height, Format, debug_d3dformat(Format),
1051 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
1053 list_init(&object->renderbuffers);
1055 /* Call the private setup routine */
1056 hr = IWineD3DSurface_PrivateSetup((IWineD3DSurface *)object);
1059 ERR("Private setup failed, returning %#x\n", hr);
1060 IWineD3DSurface_Release(*ppSurface);
1068 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
1069 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
1071 struct wined3d_rendertarget_view *object;
1073 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1076 ERR("Failed to allocate memory\n");
1077 return E_OUTOFMEMORY;
1080 object->vtbl = &wined3d_rendertarget_view_vtbl;
1081 object->refcount = 1;
1082 IWineD3DResource_AddRef(resource);
1083 object->resource = resource;
1084 object->parent = parent;
1086 *rendertarget_view = (IWineD3DRendertargetView *)object;
1091 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
1092 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
1093 WINED3DPOOL Pool, IWineD3DTexture **ppTexture, IUnknown *parent)
1095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1096 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
1097 IWineD3DTextureImpl *object;
1102 unsigned int pow2Width;
1103 unsigned int pow2Height;
1105 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1106 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
1107 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
1109 /* TODO: It should only be possible to create textures for formats
1110 that are reported as supported */
1111 if (WINED3DFMT_UNKNOWN >= Format) {
1112 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1113 return WINED3DERR_INVALIDCALL;
1116 /* Non-power2 support */
1117 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO))
1120 pow2Height = Height;
1124 /* Find the nearest pow2 match */
1125 pow2Width = pow2Height = 1;
1126 while (pow2Width < Width) pow2Width <<= 1;
1127 while (pow2Height < Height) pow2Height <<= 1;
1129 if (pow2Width != Width || pow2Height != Height)
1133 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
1134 return WINED3DERR_INVALIDCALL;
1140 /* Calculate levels for mip mapping */
1141 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1143 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1145 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1146 return WINED3DERR_INVALIDCALL;
1151 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1152 return WINED3DERR_INVALIDCALL;
1159 Levels = wined3d_log2i(max(Width, Height)) + 1;
1160 TRACE("Calculated levels = %d\n", Levels);
1163 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1166 ERR("Out of memory\n");
1168 return WINED3DERR_OUTOFVIDEOMEMORY;
1171 object->lpVtbl = &IWineD3DTexture_Vtbl;
1172 hr = resource_init(&object->resource, WINED3DRTYPE_TEXTURE, This, 0, Usage, format_desc, Pool, parent);
1175 WARN("Failed to initialize resource, returning %#x\n", hr);
1176 HeapFree(GetProcessHeap(), 0, object);
1181 TRACE("(%p) : Created resource %p\n", This, object);
1183 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1185 *ppTexture = (IWineD3DTexture *)object;
1187 basetexture_init(&object->baseTexture, Levels, Usage);
1189 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
1191 object->baseTexture.minMipLookup = minMipLookup;
1192 object->baseTexture.magLookup = magLookup;
1194 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1195 object->baseTexture.magLookup = magLookup_noFilter;
1198 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1199 /* Precalculated scaling for 'faked' non power of two texture coords.
1200 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
1201 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
1202 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
1204 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (Width != pow2Width || Height != pow2Height)) {
1205 object->baseTexture.pow2Matrix[0] = 1.0;
1206 object->baseTexture.pow2Matrix[5] = 1.0;
1207 object->baseTexture.pow2Matrix[10] = 1.0;
1208 object->baseTexture.pow2Matrix[15] = 1.0;
1209 object->target = GL_TEXTURE_2D;
1210 object->cond_np2 = TRUE;
1211 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1212 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
1213 (Width != pow2Width || Height != pow2Height) &&
1214 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
1216 if ((Width != 1) || (Height != 1)) {
1217 object->baseTexture.pow2Matrix_identity = FALSE;
1220 object->baseTexture.pow2Matrix[0] = (float)Width;
1221 object->baseTexture.pow2Matrix[5] = (float)Height;
1222 object->baseTexture.pow2Matrix[10] = 1.0;
1223 object->baseTexture.pow2Matrix[15] = 1.0;
1224 object->target = GL_TEXTURE_RECTANGLE_ARB;
1225 object->cond_np2 = TRUE;
1226 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1228 if ((Width != pow2Width) || (Height != pow2Height)) {
1229 object->baseTexture.pow2Matrix_identity = FALSE;
1230 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
1231 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
1233 object->baseTexture.pow2Matrix[0] = 1.0;
1234 object->baseTexture.pow2Matrix[5] = 1.0;
1237 object->baseTexture.pow2Matrix[10] = 1.0;
1238 object->baseTexture.pow2Matrix[15] = 1.0;
1239 object->target = GL_TEXTURE_2D;
1240 object->cond_np2 = FALSE;
1242 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
1244 /* Generate all the surfaces */
1247 for (i = 0; i < object->baseTexture.levels; i++)
1249 /* use the callback to create the texture surface */
1250 hr = IWineD3DDeviceParent_CreateSurface(This->device_parent, parent, tmpW, tmpH, Format,
1251 Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i]);
1252 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1253 FIXME("Failed to create surface %p\n", object);
1255 object->surfaces[i] = NULL;
1256 IWineD3DTexture_Release((IWineD3DTexture *)object);
1262 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1263 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1264 surface_set_texture_target(object->surfaces[i], object->target);
1265 /* calculate the next mipmap level */
1266 tmpW = max(1, tmpW >> 1);
1267 tmpH = max(1, tmpH >> 1);
1269 object->baseTexture.internal_preload = texture_internal_preload;
1271 TRACE("(%p) : Created texture %p\n", This, object);
1275 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1276 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
1277 WINED3DPOOL Pool, IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent)
1279 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1280 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
1281 IWineD3DVolumeTextureImpl *object;
1288 /* TODO: It should only be possible to create textures for formats
1289 that are reported as supported */
1290 if (WINED3DFMT_UNKNOWN >= Format) {
1291 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1292 return WINED3DERR_INVALIDCALL;
1294 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1295 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
1296 return WINED3DERR_INVALIDCALL;
1299 /* Calculate levels for mip mapping */
1300 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1302 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1304 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1305 return WINED3DERR_INVALIDCALL;
1310 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1311 return WINED3DERR_INVALIDCALL;
1318 Levels = wined3d_log2i(max(max(Width, Height), Depth)) + 1;
1319 TRACE("Calculated levels = %d\n", Levels);
1322 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1325 ERR("Out of memory\n");
1326 *ppVolumeTexture = NULL;
1327 return WINED3DERR_OUTOFVIDEOMEMORY;
1330 object->lpVtbl = &IWineD3DVolumeTexture_Vtbl;
1331 hr = resource_init(&object->resource, WINED3DRTYPE_VOLUMETEXTURE, This, 0, Usage, format_desc, Pool, parent);
1334 WARN("Failed to initialize resource, returning %#x\n", hr);
1335 HeapFree(GetProcessHeap(), 0, object);
1336 *ppVolumeTexture = NULL;
1340 TRACE("(%p) : Created resource %p\n", This, object);
1342 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1344 basetexture_init(&object->baseTexture, Levels, Usage);
1346 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1347 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1349 /* Is NP2 support for volumes needed? */
1350 object->baseTexture.pow2Matrix[ 0] = 1.0;
1351 object->baseTexture.pow2Matrix[ 5] = 1.0;
1352 object->baseTexture.pow2Matrix[10] = 1.0;
1353 object->baseTexture.pow2Matrix[15] = 1.0;
1355 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
1357 object->baseTexture.minMipLookup = minMipLookup;
1358 object->baseTexture.magLookup = magLookup;
1360 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1361 object->baseTexture.magLookup = magLookup_noFilter;
1364 /* Generate all the surfaces */
1369 for (i = 0; i < object->baseTexture.levels; i++)
1372 /* Create the volume */
1373 hr = IWineD3DDeviceParent_CreateVolume(This->device_parent, parent,
1374 tmpW, tmpH, tmpD, Format, Pool, Usage, &object->volumes[i]);
1376 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
1377 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
1378 *ppVolumeTexture = NULL;
1382 /* Set its container to this object */
1383 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1385 /* calculate the next mipmap level */
1386 tmpW = max(1, tmpW >> 1);
1387 tmpH = max(1, tmpH >> 1);
1388 tmpD = max(1, tmpD >> 1);
1390 object->baseTexture.internal_preload = volumetexture_internal_preload;
1392 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1393 TRACE("(%p) : Created volume texture %p\n", This, object);
1397 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1398 UINT Width, UINT Height, UINT Depth, DWORD Usage, WINED3DFORMAT Format,
1399 WINED3DPOOL Pool, IWineD3DVolume **ppVolume, IUnknown *parent)
1401 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1402 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1403 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &GLINFO_LOCATION);
1406 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1407 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1408 return WINED3DERR_INVALIDCALL;
1411 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1414 ERR("Out of memory\n");
1416 return WINED3DERR_OUTOFVIDEOMEMORY;
1419 object->lpVtbl = &IWineD3DVolume_Vtbl;
1420 hr = resource_init(&object->resource, WINED3DRTYPE_VOLUME, This,
1421 Width * Height * Depth * format_desc->byte_count, Usage, format_desc, Pool, parent);
1424 WARN("Failed to initialize resource, returning %#x\n", hr);
1425 HeapFree(GetProcessHeap(), 0, object);
1430 TRACE("(%p) : Created resource %p\n", This, object);
1432 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1434 *ppVolume = (IWineD3DVolume *)object;
1436 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1437 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1439 object->currentDesc.Width = Width;
1440 object->currentDesc.Height = Height;
1441 object->currentDesc.Depth = Depth;
1443 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1444 object->lockable = TRUE;
1445 object->locked = FALSE;
1446 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1447 object->dirty = TRUE;
1449 volume_add_dirty_box((IWineD3DVolume *)object, NULL);
1454 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface,
1455 UINT EdgeLength, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
1456 WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture, IUnknown *parent)
1458 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1459 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
1460 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1464 unsigned int pow2EdgeLength;
1466 /* TODO: It should only be possible to create textures for formats
1467 that are reported as supported */
1468 if (WINED3DFMT_UNKNOWN >= Format) {
1469 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1470 return WINED3DERR_INVALIDCALL;
1473 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1474 WARN("(%p) : Tried to create not supported cube texture\n", This);
1475 return WINED3DERR_INVALIDCALL;
1478 /* Calculate levels for mip mapping */
1479 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1481 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1483 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1484 return WINED3DERR_INVALIDCALL;
1489 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1490 return WINED3DERR_INVALIDCALL;
1497 Levels = wined3d_log2i(EdgeLength) + 1;
1498 TRACE("Calculated levels = %d\n", Levels);
1501 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1504 ERR("Out of memory\n");
1505 *ppCubeTexture = NULL;
1506 return WINED3DERR_OUTOFVIDEOMEMORY;
1509 object->lpVtbl = &IWineD3DCubeTexture_Vtbl;
1510 hr = resource_init(&object->resource, WINED3DRTYPE_CUBETEXTURE, This, 0, Usage, format_desc, Pool, parent);
1513 WARN("Failed to initialize resource, returning %#x\n", hr);
1514 HeapFree(GetProcessHeap(), 0, object);
1515 *ppCubeTexture = NULL;
1519 TRACE("(%p) : Created resource %p\n", This, object);
1521 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1523 basetexture_init(&object->baseTexture, Levels, Usage);
1525 TRACE("(%p) Create Cube Texture\n", This);
1527 /* Find the nearest pow2 match */
1529 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1531 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || (EdgeLength == pow2EdgeLength)) {
1532 /* Precalculated scaling for 'faked' non power of two texture coords */
1533 object->baseTexture.pow2Matrix[ 0] = 1.0;
1534 object->baseTexture.pow2Matrix[ 5] = 1.0;
1535 object->baseTexture.pow2Matrix[10] = 1.0;
1536 object->baseTexture.pow2Matrix[15] = 1.0;
1538 /* Precalculated scaling for 'faked' non power of two texture coords */
1539 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1540 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1541 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1542 object->baseTexture.pow2Matrix[15] = 1.0;
1543 object->baseTexture.pow2Matrix_identity = FALSE;
1546 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
1548 object->baseTexture.minMipLookup = minMipLookup;
1549 object->baseTexture.magLookup = magLookup;
1551 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1552 object->baseTexture.magLookup = magLookup_noFilter;
1555 /* Generate all the surfaces */
1557 for (i = 0; i < object->baseTexture.levels; i++) {
1559 /* Create the 6 faces */
1560 for (j = 0; j < 6; j++) {
1561 static const GLenum cube_targets[6] = {
1562 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
1563 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
1564 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
1565 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
1566 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
1567 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
1570 hr = IWineD3DDeviceParent_CreateSurface(This->device_parent, parent, tmpW, tmpW,
1571 Format, Usage, Pool, i /* Level */, j, &object->surfaces[j][i]);
1574 FIXME("(%p) Failed to create surface\n",object);
1575 IWineD3DCubeTexture_Release((IWineD3DCubeTexture *)object);
1576 *ppCubeTexture = NULL;
1579 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1580 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1581 surface_set_texture_target(object->surfaces[j][i], cube_targets[j]);
1583 tmpW = max(1, tmpW >> 1);
1585 object->baseTexture.internal_preload = cubetexture_internal_preload;
1587 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1588 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1592 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1593 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1594 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1595 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1596 const IWineD3DQueryVtbl *vtable;
1598 /* Just a check to see if we support this type of query */
1600 case WINED3DQUERYTYPE_OCCLUSION:
1601 TRACE("(%p) occlusion query\n", This);
1602 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1605 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1607 vtable = &IWineD3DOcclusionQuery_Vtbl;
1610 case WINED3DQUERYTYPE_EVENT:
1611 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1612 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1613 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1615 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1617 vtable = &IWineD3DEventQuery_Vtbl;
1621 case WINED3DQUERYTYPE_VCACHE:
1622 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1623 case WINED3DQUERYTYPE_VERTEXSTATS:
1624 case WINED3DQUERYTYPE_TIMESTAMP:
1625 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1626 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1627 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1628 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1629 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1630 case WINED3DQUERYTYPE_PIXELTIMINGS:
1631 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1632 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1634 /* Use the base Query vtable until we have a special one for each query */
1635 vtable = &IWineD3DQuery_Vtbl;
1636 FIXME("(%p) Unhandled query type %d\n", This, Type);
1638 if(NULL == ppQuery || hr != WINED3D_OK) {
1642 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1645 ERR("Out of memory\n");
1647 return WINED3DERR_OUTOFVIDEOMEMORY;
1650 object->lpVtbl = vtable;
1651 object->type = Type;
1652 object->state = QUERY_CREATED;
1653 object->wineD3DDevice = This;
1654 object->parent = parent;
1657 *ppQuery = (IWineD3DQuery *)object;
1659 /* allocated the 'extended' data based on the type of query requested */
1661 case WINED3DQUERYTYPE_OCCLUSION:
1662 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1663 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1665 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1666 TRACE("(%p) Allocating data for an occlusion query\n", This);
1668 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1670 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1674 case WINED3DQUERYTYPE_EVENT:
1675 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1676 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1678 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1680 if(GL_SUPPORT(APPLE_FENCE)) {
1681 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1682 checkGLcall("glGenFencesAPPLE");
1683 } else if(GL_SUPPORT(NV_FENCE)) {
1684 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1685 checkGLcall("glGenFencesNV");
1690 case WINED3DQUERYTYPE_VCACHE:
1691 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1692 case WINED3DQUERYTYPE_VERTEXSTATS:
1693 case WINED3DQUERYTYPE_TIMESTAMP:
1694 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1695 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1696 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1697 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1698 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1699 case WINED3DQUERYTYPE_PIXELTIMINGS:
1700 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1701 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1703 object->extendedData = 0;
1704 FIXME("(%p) Unhandled query type %d\n",This , Type);
1706 TRACE("(%p) : Created Query %p\n", This, object);
1710 /*****************************************************************************
1711 * IWineD3DDeviceImpl_SetupFullscreenWindow
1713 * Helper function that modifies a HWND's Style and ExStyle for proper
1717 * iface: Pointer to the IWineD3DDevice interface
1718 * window: Window to setup
1720 *****************************************************************************/
1721 static LONG fullscreen_style(LONG orig_style) {
1722 LONG style = orig_style;
1723 style &= ~WS_CAPTION;
1724 style &= ~WS_THICKFRAME;
1726 /* Make sure the window is managed, otherwise we won't get keyboard input */
1727 style |= WS_POPUP | WS_SYSMENU;
1732 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1733 LONG exStyle = orig_exStyle;
1735 /* Filter out window decorations */
1736 exStyle &= ~WS_EX_WINDOWEDGE;
1737 exStyle &= ~WS_EX_CLIENTEDGE;
1742 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1743 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1745 LONG style, exStyle;
1746 /* Don't do anything if an original style is stored.
1747 * That shouldn't happen
1749 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1750 if (This->style || This->exStyle) {
1751 ERR("(%p): Want to change the window parameters of HWND %p, but "
1752 "another style is stored for restoration afterwards\n", This, window);
1755 /* Get the parameters and save them */
1756 style = GetWindowLongW(window, GWL_STYLE);
1757 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1758 This->style = style;
1759 This->exStyle = exStyle;
1761 style = fullscreen_style(style);
1762 exStyle = fullscreen_exStyle(exStyle);
1764 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1765 This->style, This->exStyle, style, exStyle);
1767 SetWindowLongW(window, GWL_STYLE, style);
1768 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1770 /* Inform the window about the update. */
1771 SetWindowPos(window, HWND_TOP, 0, 0,
1772 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1775 /*****************************************************************************
1776 * IWineD3DDeviceImpl_RestoreWindow
1778 * Helper function that restores a windows' properties when taking it out
1779 * of fullscreen mode
1782 * iface: Pointer to the IWineD3DDevice interface
1783 * window: Window to setup
1785 *****************************************************************************/
1786 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1787 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1788 LONG style, exStyle;
1790 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1791 * switch, do nothing
1793 if (!This->style && !This->exStyle) return;
1795 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1796 This, window, This->style, This->exStyle);
1798 style = GetWindowLongW(window, GWL_STYLE);
1799 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1801 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1802 * Some applications change it before calling Reset() when switching between windowed and
1803 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1805 if(style == fullscreen_style(This->style) &&
1806 exStyle == fullscreen_style(This->exStyle)) {
1807 SetWindowLongW(window, GWL_STYLE, This->style);
1808 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1811 /* Delete the old values */
1815 /* Inform the window about the update */
1816 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1817 0, 0, 0, 0, /* Pos, Size, ignored */
1818 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1821 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1822 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1823 WINED3DPRESENT_PARAMETERS *pPresentationParameters, IWineD3DSwapChain **ppSwapChain,
1824 IUnknown *parent, WINED3DSURFTYPE surface_type)
1826 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1829 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1831 IUnknown *bufferParent;
1832 BOOL displaymode_set = FALSE;
1833 WINED3DDISPLAYMODE Mode;
1834 const struct GlPixelFormatDesc *format_desc;
1836 TRACE("(%p) : Created Additional Swap Chain\n", This);
1838 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1839 * does a device hold a reference to a swap chain giving them a lifetime of the device
1840 * or does the swap chain notify the device of its destruction.
1841 *******************************/
1843 /* Check the params */
1844 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1845 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1846 return WINED3DERR_INVALIDCALL;
1847 } else if (pPresentationParameters->BackBufferCount > 1) {
1848 FIXME("The app requests more than one back buffer, this can't be supported properly. Please configure the application to use double buffering(=1 back buffer) if possible\n");
1851 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1854 ERR("Out of memory\n");
1855 *ppSwapChain = NULL;
1856 return WINED3DERR_OUTOFVIDEOMEMORY;
1859 switch(surface_type) {
1861 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1863 case SURFACE_OPENGL:
1864 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1866 case SURFACE_UNKNOWN:
1867 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1868 HeapFree(GetProcessHeap(), 0, object);
1869 return WINED3DERR_INVALIDCALL;
1871 object->wineD3DDevice = This;
1872 object->parent = parent;
1875 *ppSwapChain = (IWineD3DSwapChain *)object;
1877 /*********************
1878 * Lookup the window Handle and the relating X window handle
1879 ********************/
1881 /* Setup hwnd we are using, plus which display this equates to */
1882 object->win_handle = pPresentationParameters->hDeviceWindow;
1883 if (!object->win_handle) {
1884 object->win_handle = This->createParms.hFocusWindow;
1886 if(!pPresentationParameters->Windowed && object->win_handle) {
1887 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1888 pPresentationParameters->BackBufferWidth,
1889 pPresentationParameters->BackBufferHeight);
1892 hDc = GetDC(object->win_handle);
1893 TRACE("Using hDc %p\n", hDc);
1896 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1897 return WINED3DERR_NOTAVAILABLE;
1900 /* Get info on the current display setup */
1901 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1902 object->orig_width = Mode.Width;
1903 object->orig_height = Mode.Height;
1904 object->orig_fmt = Mode.Format;
1905 format_desc = getFormatDescEntry(Mode.Format, &GLINFO_LOCATION);
1907 if (pPresentationParameters->Windowed &&
1908 ((pPresentationParameters->BackBufferWidth == 0) ||
1909 (pPresentationParameters->BackBufferHeight == 0) ||
1910 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1913 GetClientRect(object->win_handle, &Rect);
1915 if (pPresentationParameters->BackBufferWidth == 0) {
1916 pPresentationParameters->BackBufferWidth = Rect.right;
1917 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1919 if (pPresentationParameters->BackBufferHeight == 0) {
1920 pPresentationParameters->BackBufferHeight = Rect.bottom;
1921 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1923 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1924 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1925 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1929 /* Put the correct figures in the presentation parameters */
1930 TRACE("Copying across presentation parameters\n");
1931 object->presentParms = *pPresentationParameters;
1933 TRACE("calling rendertarget CB\n");
1934 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1935 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1936 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1937 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->frontBuffer);
1938 if (SUCCEEDED(hr)) {
1939 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1940 ((IWineD3DSurfaceImpl *)object->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
1941 if(surface_type == SURFACE_OPENGL) {
1942 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1945 ERR("Failed to create the front buffer\n");
1949 /*********************
1950 * Windowed / Fullscreen
1951 *******************/
1954 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1955 * so we should really check to see if there is a fullscreen swapchain already
1956 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1957 **************************************/
1959 if (!pPresentationParameters->Windowed) {
1960 WINED3DDISPLAYMODE mode;
1963 /* Change the display settings */
1964 mode.Width = pPresentationParameters->BackBufferWidth;
1965 mode.Height = pPresentationParameters->BackBufferHeight;
1966 mode.Format = pPresentationParameters->BackBufferFormat;
1967 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1969 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1970 displaymode_set = TRUE;
1974 * Create an opengl context for the display visual
1975 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1976 * use different properties after that point in time. FIXME: How to handle when requested format
1977 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1978 * it chooses is identical to the one already being used!
1979 **********************************/
1980 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1982 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1983 if(!object->context) {
1984 ERR("Failed to create the context array\n");
1988 object->num_contexts = 1;
1990 if(surface_type == SURFACE_OPENGL) {
1991 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1992 if (!object->context[0]) {
1993 ERR("Failed to create a new context\n");
1994 hr = WINED3DERR_NOTAVAILABLE;
1997 TRACE("Context created (HWND=%p, glContext=%p)\n",
1998 object->win_handle, object->context[0]->glCtx);
2002 /*********************
2003 * Create the back, front and stencil buffers
2004 *******************/
2005 if(object->presentParms.BackBufferCount > 0) {
2008 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
2009 if(!object->backBuffer) {
2010 ERR("Out of memory\n");
2015 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
2016 TRACE("calling rendertarget CB\n");
2017 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
2018 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
2019 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
2020 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->backBuffer[i]);
2022 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
2023 ((IWineD3DSurfaceImpl *)object->backBuffer[i])->Flags |= SFLAG_SWAPCHAIN;
2025 ERR("Cannot create new back buffer\n");
2028 if(surface_type == SURFACE_OPENGL) {
2030 glDrawBuffer(GL_BACK);
2031 checkGLcall("glDrawBuffer(GL_BACK)");
2036 object->backBuffer = NULL;
2038 /* Single buffering - draw to front buffer */
2039 if(surface_type == SURFACE_OPENGL) {
2041 glDrawBuffer(GL_FRONT);
2042 checkGLcall("glDrawBuffer(GL_FRONT)");
2047 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
2048 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
2049 TRACE("Creating depth stencil buffer\n");
2050 if (This->auto_depth_stencil_buffer == NULL ) {
2051 hr = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent, parent,
2052 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
2053 object->presentParms.AutoDepthStencilFormat, object->presentParms.MultiSampleType,
2054 object->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */,
2055 &This->auto_depth_stencil_buffer);
2056 if (SUCCEEDED(hr)) {
2057 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
2059 ERR("Failed to create the auto depth stencil\n");
2065 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
2067 TRACE("Created swapchain %p\n", object);
2068 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
2072 if (displaymode_set) {
2076 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
2079 /* Change the display settings */
2080 memset(&devmode, 0, sizeof(devmode));
2081 devmode.dmSize = sizeof(devmode);
2082 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2083 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2084 devmode.dmPelsWidth = object->orig_width;
2085 devmode.dmPelsHeight = object->orig_height;
2086 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
2089 if (object->backBuffer) {
2091 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
2092 if(object->backBuffer[i]) {
2093 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
2094 IUnknown_Release(bufferParent); /* once for the get parent */
2095 if (IUnknown_Release(bufferParent) > 0) {
2096 FIXME("(%p) Something's still holding the back buffer\n",This);
2100 HeapFree(GetProcessHeap(), 0, object->backBuffer);
2101 object->backBuffer = NULL;
2103 if(object->context && object->context[0])
2104 DestroyContext(This, object->context[0]);
2105 if(object->frontBuffer) {
2106 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
2107 IUnknown_Release(bufferParent); /* once for the get parent */
2108 if (IUnknown_Release(bufferParent) > 0) {
2109 FIXME("(%p) Something's still holding the front buffer\n",This);
2112 HeapFree(GetProcessHeap(), 0, object);
2116 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
2117 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
2118 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2119 TRACE("(%p)\n", This);
2121 return This->NumberOfSwapChains;
2124 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
2125 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2126 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
2128 if(iSwapChain < This->NumberOfSwapChains) {
2129 *pSwapChain = This->swapchains[iSwapChain];
2130 IWineD3DSwapChain_AddRef(*pSwapChain);
2131 TRACE("(%p) returning %p\n", This, *pSwapChain);
2134 TRACE("Swapchain out of range\n");
2136 return WINED3DERR_INVALIDCALL;
2141 * Vertex Declaration
2143 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
2144 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
2145 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2146 IWineD3DVertexDeclarationImpl *object = NULL;
2147 HRESULT hr = WINED3D_OK;
2149 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
2150 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
2152 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2155 ERR("Out of memory\n");
2156 *ppVertexDeclaration = NULL;
2157 return WINED3DERR_OUTOFVIDEOMEMORY;
2160 object->lpVtbl = &IWineD3DVertexDeclaration_Vtbl;
2161 object->wineD3DDevice = This;
2162 object->parent = parent;
2165 *ppVertexDeclaration = (IWineD3DVertexDeclaration *)object;
2167 hr = vertexdeclaration_init(object, elements, element_count);
2170 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
2171 *ppVertexDeclaration = NULL;
2177 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
2178 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
2180 unsigned int idx, idx2;
2181 unsigned int offset;
2182 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
2183 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
2184 BOOL has_blend_idx = has_blend &&
2185 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
2186 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
2187 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
2188 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
2189 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
2190 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
2191 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
2193 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
2194 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
2195 WINED3DVERTEXELEMENT *elements = NULL;
2198 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
2199 if (has_blend_idx) num_blends--;
2201 /* Compute declaration size */
2202 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
2203 has_psize + has_diffuse + has_specular + num_textures;
2205 /* convert the declaration */
2206 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
2207 if (!elements) return ~0U;
2211 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
2212 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
2213 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
2215 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
2216 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
2217 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
2220 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
2221 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
2223 elements[idx].usage_idx = 0;
2226 if (has_blend && (num_blends > 0)) {
2227 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
2228 elements[idx].format = WINED3DFMT_A8R8G8B8;
2230 switch(num_blends) {
2231 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
2232 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
2233 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
2234 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
2236 ERR("Unexpected amount of blend values: %u\n", num_blends);
2239 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
2240 elements[idx].usage_idx = 0;
2243 if (has_blend_idx) {
2244 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
2245 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
2246 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
2247 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
2248 elements[idx].format = WINED3DFMT_A8R8G8B8;
2250 elements[idx].format = WINED3DFMT_R32_FLOAT;
2251 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
2252 elements[idx].usage_idx = 0;
2256 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
2257 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
2258 elements[idx].usage_idx = 0;
2262 elements[idx].format = WINED3DFMT_R32_FLOAT;
2263 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
2264 elements[idx].usage_idx = 0;
2268 elements[idx].format = WINED3DFMT_A8R8G8B8;
2269 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
2270 elements[idx].usage_idx = 0;
2274 elements[idx].format = WINED3DFMT_A8R8G8B8;
2275 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
2276 elements[idx].usage_idx = 1;
2279 for (idx2 = 0; idx2 < num_textures; idx2++) {
2280 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
2281 switch (numcoords) {
2282 case WINED3DFVF_TEXTUREFORMAT1:
2283 elements[idx].format = WINED3DFMT_R32_FLOAT;
2285 case WINED3DFVF_TEXTUREFORMAT2:
2286 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
2288 case WINED3DFVF_TEXTUREFORMAT3:
2289 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
2291 case WINED3DFVF_TEXTUREFORMAT4:
2292 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
2295 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
2296 elements[idx].usage_idx = idx2;
2300 /* Now compute offsets, and initialize the rest of the fields */
2301 for (idx = 0, offset = 0; idx < size; ++idx)
2303 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
2304 elements[idx].input_slot = 0;
2305 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
2306 elements[idx].offset = offset;
2307 offset += format_desc->component_count * format_desc->component_size;
2310 *ppVertexElements = elements;
2314 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
2315 WINED3DVERTEXELEMENT* elements = NULL;
2316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2320 size = ConvertFvfToDeclaration(This, Fvf, &elements);
2321 if (size == ~0U) return WINED3DERR_OUTOFVIDEOMEMORY;
2323 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
2324 HeapFree(GetProcessHeap(), 0, elements);
2325 if (hr != S_OK) return hr;
2330 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
2331 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2332 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
2333 HRESULT hr = WINED3D_OK;
2335 if (!pFunction) return WINED3DERR_INVALIDCALL;
2337 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2340 ERR("Out of memory\n");
2341 *ppVertexShader = NULL;
2342 return WINED3DERR_OUTOFVIDEOMEMORY;
2345 object->lpVtbl = &IWineD3DVertexShader_Vtbl;
2346 object->parent = parent;
2347 shader_init(&object->baseShader, iface);
2348 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2349 *ppVertexShader = (IWineD3DVertexShader *)object;
2351 TRACE("(%p) : Created vertex shader %p\n", This, *ppVertexShader);
2353 if (vertex_declaration) {
2354 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
2357 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction, NULL);
2360 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2361 IWineD3DVertexShader_Release(*ppVertexShader);
2362 *ppVertexShader = NULL;
2369 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
2370 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
2371 IWineD3DPixelShader **ppPixelShader, IUnknown *parent)
2373 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2374 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
2375 HRESULT hr = WINED3D_OK;
2377 if (!pFunction) return WINED3DERR_INVALIDCALL;
2379 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2382 ERR("Out of memory\n");
2383 *ppPixelShader = NULL;
2384 return WINED3DERR_OUTOFVIDEOMEMORY;
2387 object->lpVtbl = &IWineD3DPixelShader_Vtbl;
2388 object->parent = parent;
2389 shader_init(&object->baseShader, iface);
2390 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2391 *ppPixelShader = (IWineD3DPixelShader *)object;
2393 TRACE("(%p) : Created pixel shader %p\n", This, *ppPixelShader);
2395 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction, output_signature);
2398 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2399 IWineD3DPixelShader_Release(*ppPixelShader);
2400 *ppPixelShader = NULL;
2407 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
2408 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
2410 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2411 IWineD3DPaletteImpl *object;
2413 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
2415 /* Create the new object */
2416 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
2418 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
2419 return E_OUTOFMEMORY;
2422 object->lpVtbl = &IWineD3DPalette_Vtbl;
2424 object->Flags = Flags;
2425 object->parent = Parent;
2426 object->wineD3DDevice = This;
2427 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2428 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2431 HeapFree( GetProcessHeap(), 0, object);
2432 return E_OUTOFMEMORY;
2435 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2437 IWineD3DPalette_Release((IWineD3DPalette *) object);
2441 *Palette = (IWineD3DPalette *) object;
2446 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
2450 HDC dcb = NULL, dcs = NULL;
2451 WINEDDCOLORKEY colorkey;
2453 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
2456 GetObjectA(hbm, sizeof(BITMAP), &bm);
2457 dcb = CreateCompatibleDC(NULL);
2459 SelectObject(dcb, hbm);
2463 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
2464 * couldn't be loaded
2466 memset(&bm, 0, sizeof(bm));
2471 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
2472 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
2473 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL, NULL);
2475 ERR("Wine logo requested, but failed to create surface\n");
2480 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
2481 if(FAILED(hr)) goto out;
2482 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
2483 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
2485 colorkey.dwColorSpaceLowValue = 0;
2486 colorkey.dwColorSpaceHighValue = 0;
2487 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2489 /* Fill the surface with a white color to show that wined3d is there */
2490 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2503 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2505 /* Under DirectX you can have texture stage operations even if no texture is
2506 bound, whereas opengl will only do texture operations when a valid texture is
2507 bound. We emulate this by creating dummy textures and binding them to each
2508 texture stage, but disable all stages by default. Hence if a stage is enabled
2509 then the default texture will kick in until replaced by a SetTexture call */
2512 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2513 /* The dummy texture does not have client storage backing */
2514 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2515 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2517 for (i = 0; i < GL_LIMITS(textures); i++) {
2518 GLubyte white = 255;
2520 /* Make appropriate texture active */
2521 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2522 checkGLcall("glActiveTextureARB");
2524 /* Generate an opengl texture name */
2525 glGenTextures(1, &This->dummyTextureName[i]);
2526 checkGLcall("glGenTextures");
2527 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2529 /* Generate a dummy 2d texture (not using 1d because they cause many
2530 * DRI drivers fall back to sw) */
2531 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2532 checkGLcall("glBindTexture");
2534 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2535 checkGLcall("glTexImage2D");
2537 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2538 /* Reenable because if supported it is enabled by default */
2539 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2540 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2546 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
2547 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2549 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2550 IWineD3DSwapChainImpl *swapchain = NULL;
2555 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
2557 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2558 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2560 /* TODO: Test if OpenGL is compiled in and loaded */
2562 TRACE("(%p) : Creating stateblock\n", This);
2563 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2564 hr = IWineD3DDevice_CreateStateBlock(iface,
2566 (IWineD3DStateBlock **)&This->stateBlock,
2568 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2569 WARN("Failed to create stateblock\n");
2572 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2573 This->updateStateBlock = This->stateBlock;
2574 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2576 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2577 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2579 This->NumberOfPalettes = 1;
2580 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2581 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2582 ERR("Out of memory!\n");
2585 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2586 if(!This->palettes[0]) {
2587 ERR("Out of memory!\n");
2590 for (i = 0; i < 256; ++i) {
2591 This->palettes[0][i].peRed = 0xFF;
2592 This->palettes[0][i].peGreen = 0xFF;
2593 This->palettes[0][i].peBlue = 0xFF;
2594 This->palettes[0][i].peFlags = 0xFF;
2596 This->currentPalette = 0;
2598 /* Initialize the texture unit mapping to a 1:1 mapping */
2599 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2600 if (state < GL_LIMITS(fragment_samplers)) {
2601 This->texUnitMap[state] = state;
2602 This->rev_tex_unit_map[state] = state;
2604 This->texUnitMap[state] = -1;
2605 This->rev_tex_unit_map[state] = -1;
2609 /* Setup the implicit swapchain */
2610 TRACE("Creating implicit swapchain\n");
2611 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2612 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2615 WARN("Failed to create implicit swapchain\n");
2619 This->NumberOfSwapChains = 1;
2620 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2621 if(!This->swapchains) {
2622 ERR("Out of memory!\n");
2625 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2627 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2628 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2629 This->render_targets[0] = swapchain->backBuffer[0];
2630 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2633 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2634 This->render_targets[0] = swapchain->frontBuffer;
2635 This->lastActiveRenderTarget = swapchain->frontBuffer;
2637 IWineD3DSurface_AddRef(This->render_targets[0]);
2638 This->activeContext = swapchain->context[0];
2639 This->lastThread = GetCurrentThreadId();
2641 /* Depth Stencil support */
2642 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2643 if (NULL != This->stencilBufferTarget) {
2644 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2647 hr = This->shader_backend->shader_alloc_private(iface);
2649 TRACE("Shader private data couldn't be allocated\n");
2652 hr = This->frag_pipe->alloc_private(iface);
2654 TRACE("Fragment pipeline private data couldn't be allocated\n");
2657 hr = This->blitter->alloc_private(iface);
2659 TRACE("Blitter private data couldn't be allocated\n");
2663 /* Set up some starting GL setup */
2665 /* Setup all the devices defaults */
2666 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2667 create_dummy_textures(This);
2671 /* Initialize the current view state */
2672 This->view_ident = 1;
2673 This->contexts[0]->last_was_rhw = 0;
2674 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2675 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2677 switch(wined3d_settings.offscreen_rendering_mode) {
2680 This->offscreenBuffer = GL_BACK;
2683 case ORM_BACKBUFFER:
2685 if(This->activeContext->aux_buffers > 0) {
2686 TRACE("Using auxilliary buffer for offscreen rendering\n");
2687 This->offscreenBuffer = GL_AUX0;
2689 TRACE("Using back buffer for offscreen rendering\n");
2690 This->offscreenBuffer = GL_BACK;
2695 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2698 /* Clear the screen */
2699 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2700 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2703 This->d3d_initialized = TRUE;
2705 if(wined3d_settings.logo) {
2706 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2708 This->highest_dirty_ps_const = 0;
2709 This->highest_dirty_vs_const = 0;
2713 HeapFree(GetProcessHeap(), 0, This->render_targets);
2714 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2715 HeapFree(GetProcessHeap(), 0, This->swapchains);
2716 This->NumberOfSwapChains = 0;
2717 if(This->palettes) {
2718 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2719 HeapFree(GetProcessHeap(), 0, This->palettes);
2721 This->NumberOfPalettes = 0;
2723 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2725 if(This->stateBlock) {
2726 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2727 This->stateBlock = NULL;
2729 if (This->blit_priv) {
2730 This->blitter->free_private(iface);
2732 if (This->fragment_priv) {
2733 This->frag_pipe->free_private(iface);
2735 if (This->shader_priv) {
2736 This->shader_backend->shader_free_private(iface);
2741 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2742 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2745 IWineD3DSwapChainImpl *swapchain = NULL;
2748 /* Setup the implicit swapchain */
2749 TRACE("Creating implicit swapchain\n");
2750 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2751 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2754 WARN("Failed to create implicit swapchain\n");
2758 This->NumberOfSwapChains = 1;
2759 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2760 if(!This->swapchains) {
2761 ERR("Out of memory!\n");
2764 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2768 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2772 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2774 IWineD3DResource_UnLoad(resource);
2775 IWineD3DResource_Release(resource);
2779 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2780 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2783 TRACE("(%p)\n", This);
2785 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2787 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2788 * it was created. Thus make sure a context is active for the glDelete* calls
2790 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2792 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2794 /* Unload resources */
2795 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2797 TRACE("Deleting high order patches\n");
2798 for(i = 0; i < PATCHMAP_SIZE; i++) {
2799 struct list *e1, *e2;
2800 struct WineD3DRectPatch *patch;
2801 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2802 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2803 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2807 /* Delete the palette conversion shader if it is around */
2808 if(This->paletteConversionShader) {
2810 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2812 This->paletteConversionShader = 0;
2815 /* Delete the pbuffer context if there is any */
2816 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2818 /* Delete the mouse cursor texture */
2819 if(This->cursorTexture) {
2821 glDeleteTextures(1, &This->cursorTexture);
2823 This->cursorTexture = 0;
2826 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2827 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2829 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2830 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2833 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2834 * private data, it might contain opengl pointers
2836 if(This->depth_blt_texture) {
2837 glDeleteTextures(1, &This->depth_blt_texture);
2838 This->depth_blt_texture = 0;
2840 if (This->depth_blt_rb) {
2841 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2842 This->depth_blt_rb = 0;
2843 This->depth_blt_rb_w = 0;
2844 This->depth_blt_rb_h = 0;
2847 /* Release the update stateblock */
2848 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2849 if(This->updateStateBlock != This->stateBlock)
2850 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2852 This->updateStateBlock = NULL;
2854 { /* because were not doing proper internal refcounts releasing the primary state block
2855 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2856 to set this->stateBlock = NULL; first */
2857 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2858 This->stateBlock = NULL;
2860 /* Release the stateblock */
2861 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2862 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2866 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2867 This->blitter->free_private(iface);
2868 This->frag_pipe->free_private(iface);
2869 This->shader_backend->shader_free_private(iface);
2871 /* Release the buffers (with sanity checks)*/
2872 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2873 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2874 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2875 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2877 This->stencilBufferTarget = NULL;
2879 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2880 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2881 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2883 TRACE("Setting rendertarget to NULL\n");
2884 This->render_targets[0] = NULL;
2886 if (This->auto_depth_stencil_buffer) {
2887 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2888 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2890 This->auto_depth_stencil_buffer = NULL;
2893 for(i=0; i < This->NumberOfSwapChains; i++) {
2894 TRACE("Releasing the implicit swapchain %d\n", i);
2895 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2896 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2900 HeapFree(GetProcessHeap(), 0, This->swapchains);
2901 This->swapchains = NULL;
2902 This->NumberOfSwapChains = 0;
2904 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2905 HeapFree(GetProcessHeap(), 0, This->palettes);
2906 This->palettes = NULL;
2907 This->NumberOfPalettes = 0;
2909 HeapFree(GetProcessHeap(), 0, This->render_targets);
2910 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2911 This->render_targets = NULL;
2912 This->draw_buffers = NULL;
2914 This->d3d_initialized = FALSE;
2918 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2919 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2922 for(i=0; i < This->NumberOfSwapChains; i++) {
2923 TRACE("Releasing the implicit swapchain %d\n", i);
2924 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2925 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2929 HeapFree(GetProcessHeap(), 0, This->swapchains);
2930 This->swapchains = NULL;
2931 This->NumberOfSwapChains = 0;
2935 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2936 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2937 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2939 * There is no way to deactivate thread safety once it is enabled.
2941 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2942 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2944 /*For now just store the flag(needed in case of ddraw) */
2945 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2950 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2951 const WINED3DDISPLAYMODE* pMode) {
2953 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2955 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &GLINFO_LOCATION);
2958 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2960 /* Resize the screen even without a window:
2961 * The app could have unset it with SetCooperativeLevel, but not called
2962 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2963 * but we don't have any hwnd
2966 memset(&devmode, 0, sizeof(devmode));
2967 devmode.dmSize = sizeof(devmode);
2968 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2969 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2970 devmode.dmPelsWidth = pMode->Width;
2971 devmode.dmPelsHeight = pMode->Height;
2973 devmode.dmDisplayFrequency = pMode->RefreshRate;
2974 if (pMode->RefreshRate != 0) {
2975 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2978 /* Only change the mode if necessary */
2979 if( (This->ddraw_width == pMode->Width) &&
2980 (This->ddraw_height == pMode->Height) &&
2981 (This->ddraw_format == pMode->Format) &&
2982 (pMode->RefreshRate == 0) ) {
2986 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2987 if (ret != DISP_CHANGE_SUCCESSFUL) {
2988 if(devmode.dmDisplayFrequency != 0) {
2989 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2990 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2991 devmode.dmDisplayFrequency = 0;
2992 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2994 if(ret != DISP_CHANGE_SUCCESSFUL) {
2995 return WINED3DERR_NOTAVAILABLE;
2999 /* Store the new values */
3000 This->ddraw_width = pMode->Width;
3001 This->ddraw_height = pMode->Height;
3002 This->ddraw_format = pMode->Format;
3004 /* And finally clip mouse to our screen */
3005 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
3006 ClipCursor(&clip_rc);
3011 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
3012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3013 *ppD3D= This->wineD3D;
3014 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
3015 IWineD3D_AddRef(*ppD3D);
3019 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
3020 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3022 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
3023 (This->adapter->TextureRam/(1024*1024)),
3024 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
3025 /* return simulated texture memory left */
3026 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
3030 * Get / Set Stream Source
3032 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
3033 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
3035 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3036 IWineD3DBuffer *oldSrc;
3038 if (StreamNumber >= MAX_STREAMS) {
3039 WARN("Stream out of range %d\n", StreamNumber);
3040 return WINED3DERR_INVALIDCALL;
3041 } else if(OffsetInBytes & 0x3) {
3042 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
3043 return WINED3DERR_INVALIDCALL;
3046 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
3047 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
3049 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
3051 if(oldSrc == pStreamData &&
3052 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
3053 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
3054 TRACE("Application is setting the old values over, nothing to do\n");
3058 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
3060 This->updateStateBlock->streamStride[StreamNumber] = Stride;
3061 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
3064 /* Handle recording of state blocks */
3065 if (This->isRecordingState) {
3066 TRACE("Recording... not performing anything\n");
3067 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
3068 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
3072 if (pStreamData != NULL) {
3073 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
3074 IWineD3DBuffer_AddRef(pStreamData);
3076 if (oldSrc != NULL) {
3077 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
3078 IWineD3DBuffer_Release(oldSrc);
3081 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3086 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
3087 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
3089 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3091 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
3092 This->stateBlock->streamSource[StreamNumber],
3093 This->stateBlock->streamOffset[StreamNumber],
3094 This->stateBlock->streamStride[StreamNumber]);
3096 if (StreamNumber >= MAX_STREAMS) {
3097 WARN("Stream out of range %d\n", StreamNumber);
3098 return WINED3DERR_INVALIDCALL;
3100 *pStream = This->stateBlock->streamSource[StreamNumber];
3101 *pStride = This->stateBlock->streamStride[StreamNumber];
3103 *pOffset = This->stateBlock->streamOffset[StreamNumber];
3106 if (*pStream != NULL) {
3107 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
3112 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
3113 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3114 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
3115 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
3117 /* Verify input at least in d3d9 this is invalid*/
3118 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
3119 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
3120 return WINED3DERR_INVALIDCALL;
3122 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
3123 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
3124 return WINED3DERR_INVALIDCALL;
3127 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
3128 return WINED3DERR_INVALIDCALL;
3131 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
3132 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
3134 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
3135 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
3137 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
3138 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
3139 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3145 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
3146 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3148 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
3149 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
3151 TRACE("(%p) : returning %d\n", This, *Divider);
3157 * Get / Set & Multiply Transform
3159 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
3160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3162 /* Most of this routine, comments included copied from ddraw tree initially: */
3163 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
3165 /* Handle recording of state blocks */
3166 if (This->isRecordingState) {
3167 TRACE("Recording... not performing anything\n");
3168 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
3169 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
3174 * If the new matrix is the same as the current one,
3175 * we cut off any further processing. this seems to be a reasonable
3176 * optimization because as was noticed, some apps (warcraft3 for example)
3177 * tend towards setting the same matrix repeatedly for some reason.
3179 * From here on we assume that the new matrix is different, wherever it matters.
3181 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
3182 TRACE("The app is setting the same matrix over again\n");
3185 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
3189 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
3190 where ViewMat = Camera space, WorldMat = world space.
3192 In OpenGL, camera and world space is combined into GL_MODELVIEW
3193 matrix. The Projection matrix stay projection matrix.
3196 /* Capture the times we can just ignore the change for now */
3197 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
3198 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
3199 /* Handled by the state manager */
3202 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
3206 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
3207 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3208 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
3209 *pMatrix = This->stateBlock->transforms[State];
3213 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
3214 const WINED3DMATRIX *mat = NULL;
3217 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
3218 * below means it will be recorded in a state block change, but it
3219 * works regardless where it is recorded.
3220 * If this is found to be wrong, change to StateBlock.
3222 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3223 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
3225 if (State <= HIGHEST_TRANSFORMSTATE)
3227 mat = &This->updateStateBlock->transforms[State];
3229 FIXME("Unhandled transform state!!\n");
3232 multiply_matrix(&temp, mat, pMatrix);
3234 /* Apply change via set transform - will reapply to eg. lights this way */
3235 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
3241 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
3242 you can reference any indexes you want as long as that number max are enabled at any
3243 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
3244 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
3245 but when recording, just build a chain pretty much of commands to be replayed. */
3247 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
3249 PLIGHTINFOEL *object = NULL;
3250 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3253 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3254 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
3256 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
3260 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
3261 return WINED3DERR_INVALIDCALL;
3264 switch(pLight->Type) {
3265 case WINED3DLIGHT_POINT:
3266 case WINED3DLIGHT_SPOT:
3267 case WINED3DLIGHT_PARALLELPOINT:
3268 case WINED3DLIGHT_GLSPOT:
3269 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
3272 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
3273 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
3274 return WINED3DERR_INVALIDCALL;
3278 case WINED3DLIGHT_DIRECTIONAL:
3279 /* Ignores attenuation */
3283 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
3284 return WINED3DERR_INVALIDCALL;
3287 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3288 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3289 if(object->OriginalIndex == Index) break;
3294 TRACE("Adding new light\n");
3295 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
3297 ERR("Out of memory error when allocating a light\n");
3298 return E_OUTOFMEMORY;
3300 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
3301 object->glIndex = -1;
3302 object->OriginalIndex = Index;
3303 object->changed = TRUE;
3306 /* Initialize the object */
3307 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,
3308 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
3309 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
3310 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
3311 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
3312 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
3313 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
3315 /* Save away the information */
3316 object->OriginalParms = *pLight;
3318 switch (pLight->Type) {
3319 case WINED3DLIGHT_POINT:
3321 object->lightPosn[0] = pLight->Position.x;
3322 object->lightPosn[1] = pLight->Position.y;
3323 object->lightPosn[2] = pLight->Position.z;
3324 object->lightPosn[3] = 1.0f;
3325 object->cutoff = 180.0f;
3329 case WINED3DLIGHT_DIRECTIONAL:
3331 object->lightPosn[0] = -pLight->Direction.x;
3332 object->lightPosn[1] = -pLight->Direction.y;
3333 object->lightPosn[2] = -pLight->Direction.z;
3334 object->lightPosn[3] = 0.0;
3335 object->exponent = 0.0f;
3336 object->cutoff = 180.0f;
3339 case WINED3DLIGHT_SPOT:
3341 object->lightPosn[0] = pLight->Position.x;
3342 object->lightPosn[1] = pLight->Position.y;
3343 object->lightPosn[2] = pLight->Position.z;
3344 object->lightPosn[3] = 1.0;
3347 object->lightDirn[0] = pLight->Direction.x;
3348 object->lightDirn[1] = pLight->Direction.y;
3349 object->lightDirn[2] = pLight->Direction.z;
3350 object->lightDirn[3] = 1.0;
3353 * opengl-ish and d3d-ish spot lights use too different models for the
3354 * light "intensity" as a function of the angle towards the main light direction,
3355 * so we only can approximate very roughly.
3356 * however spot lights are rather rarely used in games (if ever used at all).
3357 * furthermore if still used, probably nobody pays attention to such details.
3359 if (pLight->Falloff == 0) {
3360 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
3361 * falloff resp. exponent parameter as an exponent, so the spot light lighting
3362 * will always be 1.0 for both of them, and we don't have to care for the
3363 * rest of the rather complex calculation
3365 object->exponent = 0;
3367 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
3368 if (rho < 0.0001) rho = 0.0001f;
3369 object->exponent = -0.3/log(cos(rho/2));
3371 if (object->exponent > 128.0) {
3372 object->exponent = 128.0;
3374 object->cutoff = pLight->Phi*90/M_PI;
3380 FIXME("Unrecognized light type %d\n", pLight->Type);
3383 /* Update the live definitions if the light is currently assigned a glIndex */
3384 if (object->glIndex != -1 && !This->isRecordingState) {
3385 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
3390 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
3391 PLIGHTINFOEL *lightInfo = NULL;
3392 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3393 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
3395 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
3397 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3398 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3399 if(lightInfo->OriginalIndex == Index) break;
3403 if (lightInfo == NULL) {
3404 TRACE("Light information requested but light not defined\n");
3405 return WINED3DERR_INVALIDCALL;
3408 *pLight = lightInfo->OriginalParms;
3413 * Get / Set Light Enable
3414 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
3416 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
3417 PLIGHTINFOEL *lightInfo = NULL;
3418 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3419 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3421 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
3423 /* Tests show true = 128...not clear why */
3424 Enable = Enable? 128: 0;
3426 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3427 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3428 if(lightInfo->OriginalIndex == Index) break;
3431 TRACE("Found light: %p\n", lightInfo);
3433 /* Special case - enabling an undefined light creates one with a strict set of parms! */
3434 if (lightInfo == NULL) {
3436 TRACE("Light enabled requested but light not defined, so defining one!\n");
3437 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
3439 /* Search for it again! Should be fairly quick as near head of list */
3440 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3441 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3442 if(lightInfo->OriginalIndex == Index) break;
3445 if (lightInfo == NULL) {
3446 FIXME("Adding default lights has failed dismally\n");
3447 return WINED3DERR_INVALIDCALL;
3451 lightInfo->enabledChanged = TRUE;
3453 if(lightInfo->glIndex != -1) {
3454 if(!This->isRecordingState) {
3455 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
3458 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
3459 lightInfo->glIndex = -1;
3461 TRACE("Light already disabled, nothing to do\n");
3463 lightInfo->enabled = FALSE;
3465 lightInfo->enabled = TRUE;
3466 if (lightInfo->glIndex != -1) {
3468 TRACE("Nothing to do as light was enabled\n");
3471 /* Find a free gl light */
3472 for(i = 0; i < This->maxConcurrentLights; i++) {
3473 if(This->updateStateBlock->activeLights[i] == NULL) {
3474 This->updateStateBlock->activeLights[i] = lightInfo;
3475 lightInfo->glIndex = i;
3479 if(lightInfo->glIndex == -1) {
3480 /* Our tests show that Windows returns D3D_OK in this situation, even with
3481 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3482 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3483 * as well for those lights.
3485 * TODO: Test how this affects rendering
3487 WARN("Too many concurrently active lights\n");
3491 /* i == lightInfo->glIndex */
3492 if(!This->isRecordingState) {
3493 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3501 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3503 PLIGHTINFOEL *lightInfo = NULL;
3504 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3506 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3507 TRACE("(%p) : for idx(%d)\n", This, Index);
3509 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3510 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3511 if(lightInfo->OriginalIndex == Index) break;
3515 if (lightInfo == NULL) {
3516 TRACE("Light enabled state requested but light not defined\n");
3517 return WINED3DERR_INVALIDCALL;
3519 /* true is 128 according to SetLightEnable */
3520 *pEnable = lightInfo->enabled ? 128 : 0;
3525 * Get / Set Clip Planes
3527 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3528 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3529 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3531 /* Validate Index */
3532 if (Index >= GL_LIMITS(clipplanes)) {
3533 TRACE("Application has requested clipplane this device doesn't support\n");
3534 return WINED3DERR_INVALIDCALL;
3537 This->updateStateBlock->changed.clipplane |= 1 << Index;
3539 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3540 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3541 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3542 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3543 TRACE("Application is setting old values over, nothing to do\n");
3547 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3548 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3549 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3550 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3552 /* Handle recording of state blocks */
3553 if (This->isRecordingState) {
3554 TRACE("Recording... not performing anything\n");
3558 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3563 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3564 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3565 TRACE("(%p) : for idx %d\n", This, Index);
3567 /* Validate Index */
3568 if (Index >= GL_LIMITS(clipplanes)) {
3569 TRACE("Application has requested clipplane this device doesn't support\n");
3570 return WINED3DERR_INVALIDCALL;
3573 pPlane[0] = This->stateBlock->clipplane[Index][0];
3574 pPlane[1] = This->stateBlock->clipplane[Index][1];
3575 pPlane[2] = This->stateBlock->clipplane[Index][2];
3576 pPlane[3] = This->stateBlock->clipplane[Index][3];
3581 * Get / Set Clip Plane Status
3582 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3584 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3585 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3586 FIXME("(%p) : stub\n", This);
3587 if (NULL == pClipStatus) {
3588 return WINED3DERR_INVALIDCALL;
3590 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3591 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3595 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3596 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3597 FIXME("(%p) : stub\n", This);
3598 if (NULL == pClipStatus) {
3599 return WINED3DERR_INVALIDCALL;
3601 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3602 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3607 * Get / Set Material
3609 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3610 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3612 This->updateStateBlock->changed.material = TRUE;
3613 This->updateStateBlock->material = *pMaterial;
3615 /* Handle recording of state blocks */
3616 if (This->isRecordingState) {
3617 TRACE("Recording... not performing anything\n");
3621 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3625 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3626 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3627 *pMaterial = This->updateStateBlock->material;
3628 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3629 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3630 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3631 pMaterial->Ambient.b, pMaterial->Ambient.a);
3632 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3633 pMaterial->Specular.b, pMaterial->Specular.a);
3634 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3635 pMaterial->Emissive.b, pMaterial->Emissive.a);
3636 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3644 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DBuffer* pIndexData, WINED3DFORMAT fmt) {
3645 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3646 IWineD3DBuffer *oldIdxs;
3648 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3649 oldIdxs = This->updateStateBlock->pIndexData;
3651 This->updateStateBlock->changed.indices = TRUE;
3652 This->updateStateBlock->pIndexData = pIndexData;
3653 This->updateStateBlock->IndexFmt = fmt;
3655 /* Handle recording of state blocks */
3656 if (This->isRecordingState) {
3657 TRACE("Recording... not performing anything\n");
3658 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
3659 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
3663 if(oldIdxs != pIndexData) {
3664 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3666 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
3667 IWineD3DBuffer_AddRef(pIndexData);
3670 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
3671 IWineD3DBuffer_Release(oldIdxs);
3678 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DBuffer** ppIndexData) {
3679 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3681 *ppIndexData = This->stateBlock->pIndexData;
3683 /* up ref count on ppindexdata */
3685 IWineD3DBuffer_AddRef(*ppIndexData);
3686 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3688 TRACE("(%p) No index data set\n", This);
3690 TRACE("Returning %p\n", *ppIndexData);
3695 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3696 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3697 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3698 TRACE("(%p)->(%d)\n", This, BaseIndex);
3700 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3701 TRACE("Application is setting the old value over, nothing to do\n");
3705 This->updateStateBlock->baseVertexIndex = BaseIndex;
3707 if (This->isRecordingState) {
3708 TRACE("Recording... not performing anything\n");
3711 /* The base vertex index affects the stream sources */
3712 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3716 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3717 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3718 TRACE("(%p) : base_index %p\n", This, base_index);
3720 *base_index = This->stateBlock->baseVertexIndex;
3722 TRACE("Returning %u\n", *base_index);
3728 * Get / Set Viewports
3730 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3731 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3733 TRACE("(%p)\n", This);
3734 This->updateStateBlock->changed.viewport = TRUE;
3735 This->updateStateBlock->viewport = *pViewport;
3737 /* Handle recording of state blocks */
3738 if (This->isRecordingState) {
3739 TRACE("Recording... not performing anything\n");
3743 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3744 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3746 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3751 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3752 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3753 TRACE("(%p)\n", This);
3754 *pViewport = This->stateBlock->viewport;
3759 * Get / Set Render States
3760 * TODO: Verify against dx9 definitions
3762 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3765 DWORD oldValue = This->stateBlock->renderState[State];
3767 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3769 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3770 This->updateStateBlock->renderState[State] = Value;
3772 /* Handle recording of state blocks */
3773 if (This->isRecordingState) {
3774 TRACE("Recording... not performing anything\n");
3778 /* Compared here and not before the assignment to allow proper stateblock recording */
3779 if(Value == oldValue) {
3780 TRACE("Application is setting the old value over, nothing to do\n");
3782 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3788 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3789 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3790 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3791 *pValue = This->stateBlock->renderState[State];
3796 * Get / Set Sampler States
3797 * TODO: Verify against dx9 definitions
3800 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3801 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3804 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3805 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3807 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3808 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3811 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3812 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3813 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3816 * SetSampler is designed to allow for more than the standard up to 8 textures
3817 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3818 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3820 * http://developer.nvidia.com/object/General_FAQ.html#t6
3822 * There are two new settings for GForce
3824 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3825 * and the texture one:
3826 * GL_MAX_TEXTURE_COORDS_ARB.
3827 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3830 oldValue = This->stateBlock->samplerState[Sampler][Type];
3831 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3832 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3834 /* Handle recording of state blocks */
3835 if (This->isRecordingState) {
3836 TRACE("Recording... not performing anything\n");
3840 if(oldValue == Value) {
3841 TRACE("Application is setting the old value over, nothing to do\n");
3845 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3850 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3851 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3853 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3854 This, Sampler, debug_d3dsamplerstate(Type), Type);
3856 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3857 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3860 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3861 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3862 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3864 *Value = This->stateBlock->samplerState[Sampler][Type];
3865 TRACE("(%p) : Returning %#x\n", This, *Value);
3870 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3871 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3873 This->updateStateBlock->changed.scissorRect = TRUE;
3874 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3875 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3878 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3880 if(This->isRecordingState) {
3881 TRACE("Recording... not performing anything\n");
3885 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3890 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3891 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3893 *pRect = This->updateStateBlock->scissorRect;
3894 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3898 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3899 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3900 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3902 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3904 This->updateStateBlock->vertexDecl = pDecl;
3905 This->updateStateBlock->changed.vertexDecl = TRUE;
3907 if (This->isRecordingState) {
3908 TRACE("Recording... not performing anything\n");
3910 } else if(pDecl == oldDecl) {
3911 /* Checked after the assignment to allow proper stateblock recording */
3912 TRACE("Application is setting the old declaration over, nothing to do\n");
3916 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3920 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3921 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3923 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3925 *ppDecl = This->stateBlock->vertexDecl;
3926 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3930 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3931 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3932 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3934 This->updateStateBlock->vertexShader = pShader;
3935 This->updateStateBlock->changed.vertexShader = TRUE;
3937 if (This->isRecordingState) {
3938 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3939 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3940 TRACE("Recording... not performing anything\n");
3942 } else if(oldShader == pShader) {
3943 /* Checked here to allow proper stateblock recording */
3944 TRACE("App is setting the old shader over, nothing to do\n");
3948 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3949 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3950 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3952 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3957 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3958 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3960 if (NULL == ppShader) {
3961 return WINED3DERR_INVALIDCALL;
3963 *ppShader = This->stateBlock->vertexShader;
3964 if( NULL != *ppShader)
3965 IWineD3DVertexShader_AddRef(*ppShader);
3967 TRACE("(%p) : returning %p\n", This, *ppShader);
3971 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3972 IWineD3DDevice *iface,
3974 CONST BOOL *srcData,
3977 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3978 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3980 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3981 iface, srcData, start, count);
3983 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3985 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3986 for (i = 0; i < cnt; i++)
3987 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3989 for (i = start; i < cnt + start; ++i) {
3990 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3993 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3998 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3999 IWineD3DDevice *iface,
4004 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4005 int cnt = min(count, MAX_CONST_B - start);
4007 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4008 iface, dstData, start, count);
4010 if (dstData == NULL || cnt < 0)
4011 return WINED3DERR_INVALIDCALL;
4013 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
4017 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
4018 IWineD3DDevice *iface,
4023 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4024 unsigned int i, cnt = min(count, MAX_CONST_I - start);
4026 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4027 iface, srcData, start, count);
4029 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
4031 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4032 for (i = 0; i < cnt; i++)
4033 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4034 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4036 for (i = start; i < cnt + start; ++i) {
4037 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
4040 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
4045 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
4046 IWineD3DDevice *iface,
4051 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4052 int cnt = min(count, MAX_CONST_I - start);
4054 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4055 iface, dstData, start, count);
4057 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
4058 return WINED3DERR_INVALIDCALL;
4060 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4064 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
4065 IWineD3DDevice *iface,
4067 CONST float *srcData,
4070 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4073 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4074 iface, srcData, start, count);
4076 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4077 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
4078 return WINED3DERR_INVALIDCALL;
4080 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4082 for (i = 0; i < count; i++)
4083 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4084 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4087 if (!This->isRecordingState)
4089 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
4090 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
4093 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
4094 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
4099 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
4100 IWineD3DDevice *iface,
4105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4106 int cnt = min(count, This->d3d_vshader_constantF - start);
4108 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4109 iface, dstData, start, count);
4111 if (dstData == NULL || cnt < 0)
4112 return WINED3DERR_INVALIDCALL;
4114 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4118 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
4120 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
4122 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
4126 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
4127 int i = This->rev_tex_unit_map[unit];
4128 int j = This->texUnitMap[stage];
4130 This->texUnitMap[stage] = unit;
4131 if (i != -1 && i != stage) {
4132 This->texUnitMap[i] = -1;
4135 This->rev_tex_unit_map[unit] = stage;
4136 if (j != -1 && j != unit) {
4137 This->rev_tex_unit_map[j] = -1;
4141 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
4144 This->fixed_function_usage_map = 0;
4145 for (i = 0; i < MAX_TEXTURES; ++i) {
4146 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
4147 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
4148 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
4149 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
4150 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
4151 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
4152 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
4153 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
4155 if (color_op == WINED3DTOP_DISABLE) {
4156 /* Not used, and disable higher stages */
4160 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
4161 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
4162 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
4163 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
4164 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
4165 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
4166 This->fixed_function_usage_map |= (1 << i);
4169 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
4170 This->fixed_function_usage_map |= (1 << (i + 1));
4175 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
4176 unsigned int i, tex;
4179 device_update_fixed_function_usage_map(This);
4180 ffu_map = This->fixed_function_usage_map;
4182 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
4183 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
4184 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
4186 if (!(ffu_map & 1)) continue;
4188 if (This->texUnitMap[i] != i) {
4189 device_map_stage(This, i, i);
4190 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
4191 markTextureStagesDirty(This, i);
4197 /* Now work out the mapping */
4199 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
4201 if (!(ffu_map & 1)) continue;
4203 if (This->texUnitMap[i] != tex) {
4204 device_map_stage(This, i, tex);
4205 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
4206 markTextureStagesDirty(This, i);
4213 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
4214 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
4215 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
4218 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
4219 if (sampler_type[i] && This->texUnitMap[i] != i)
4221 device_map_stage(This, i, i);
4222 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
4223 if (i < MAX_TEXTURES) {
4224 markTextureStagesDirty(This, i);
4230 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
4231 const DWORD *vshader_sampler_tokens, int unit)
4233 int current_mapping = This->rev_tex_unit_map[unit];
4235 if (current_mapping == -1) {
4236 /* Not currently used */
4240 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
4241 /* Used by a fragment sampler */
4243 if (!pshader_sampler_tokens) {
4244 /* No pixel shader, check fixed function */
4245 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
4248 /* Pixel shader, check the shader's sampler map */
4249 return !pshader_sampler_tokens[current_mapping];
4252 /* Used by a vertex sampler */
4253 return !vshader_sampler_tokens[current_mapping];
4256 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
4257 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
4258 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
4259 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
4260 int start = GL_LIMITS(combined_samplers) - 1;
4264 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
4266 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
4267 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
4268 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
4271 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
4272 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
4273 if (vshader_sampler_type[i])
4275 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
4277 /* Already mapped somewhere */
4281 while (start >= 0) {
4282 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
4284 device_map_stage(This, vsampler_idx, start);
4285 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
4297 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
4298 BOOL vs = use_vs(This->stateBlock);
4299 BOOL ps = use_ps(This->stateBlock);
4302 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
4303 * that would be really messy and require shader recompilation
4304 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
4305 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
4308 device_map_psamplers(This);
4310 device_map_fixed_function_samplers(This);
4314 device_map_vsamplers(This, ps);
4318 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4319 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4320 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4321 This->updateStateBlock->pixelShader = pShader;
4322 This->updateStateBlock->changed.pixelShader = TRUE;
4324 /* Handle recording of state blocks */
4325 if (This->isRecordingState) {
4326 TRACE("Recording... not performing anything\n");
4329 if (This->isRecordingState) {
4330 TRACE("Recording... not performing anything\n");
4331 if(pShader) IWineD3DPixelShader_AddRef(pShader);
4332 if(oldShader) IWineD3DPixelShader_Release(oldShader);
4336 if(pShader == oldShader) {
4337 TRACE("App is setting the old pixel shader over, nothing to do\n");
4341 if(pShader) IWineD3DPixelShader_AddRef(pShader);
4342 if(oldShader) IWineD3DPixelShader_Release(oldShader);
4344 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4345 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4350 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4353 if (NULL == ppShader) {
4354 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4355 return WINED3DERR_INVALIDCALL;
4358 *ppShader = This->stateBlock->pixelShader;
4359 if (NULL != *ppShader) {
4360 IWineD3DPixelShader_AddRef(*ppShader);
4362 TRACE("(%p) : returning %p\n", This, *ppShader);
4366 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4367 IWineD3DDevice *iface,
4369 CONST BOOL *srcData,
4372 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4373 unsigned int i, cnt = min(count, MAX_CONST_B - start);
4375 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
4376 iface, srcData, start, count);
4378 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
4380 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4381 for (i = 0; i < cnt; i++)
4382 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4384 for (i = start; i < cnt + start; ++i) {
4385 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
4388 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4393 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4394 IWineD3DDevice *iface,
4399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4400 int cnt = min(count, MAX_CONST_B - start);
4402 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4403 iface, dstData, start, count);
4405 if (dstData == NULL || cnt < 0)
4406 return WINED3DERR_INVALIDCALL;
4408 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4412 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4413 IWineD3DDevice *iface,
4418 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4419 unsigned int i, cnt = min(count, MAX_CONST_I - start);
4421 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
4422 iface, srcData, start, count);
4424 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
4426 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4427 for (i = 0; i < cnt; i++)
4428 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4429 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4431 for (i = start; i < cnt + start; ++i) {
4432 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
4435 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4440 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4441 IWineD3DDevice *iface,
4446 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4447 int cnt = min(count, MAX_CONST_I - start);
4449 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4450 iface, dstData, start, count);
4452 if (dstData == NULL || cnt < 0)
4453 return WINED3DERR_INVALIDCALL;
4455 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4459 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4460 IWineD3DDevice *iface,
4462 CONST float *srcData,
4465 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4468 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4469 iface, srcData, start, count);
4471 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4472 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
4473 return WINED3DERR_INVALIDCALL;
4475 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4477 for (i = 0; i < count; i++)
4478 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4479 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4482 if (!This->isRecordingState)
4484 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
4485 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4488 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
4489 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
4494 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4495 IWineD3DDevice *iface,
4500 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4501 int cnt = min(count, This->d3d_pshader_constantF - start);
4503 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4504 iface, dstData, start, count);
4506 if (dstData == NULL || cnt < 0)
4507 return WINED3DERR_INVALIDCALL;
4509 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4513 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4514 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4515 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
4518 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4521 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4525 if (stream_info->elements[WINED3D_FFP_NORMAL].data)
4527 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4530 if (!stream_info->elements[WINED3D_FFP_POSITION].data)
4532 ERR("Source has no position mask\n");
4533 return WINED3DERR_INVALIDCALL;
4536 /* We might access VBOs from this code, so hold the lock */
4539 if (dest->resource.allocatedMemory == NULL) {
4540 buffer_get_sysmem(dest);
4543 /* Get a pointer into the destination vbo(create one if none exists) and
4544 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4546 if (!dest->buffer_object && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT))
4548 dest->flags |= WINED3D_BUFFER_CREATEBO;
4549 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
4552 if (dest->buffer_object)
4554 unsigned char extrabytes = 0;
4555 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4556 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4557 * this may write 4 extra bytes beyond the area that should be written
4559 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4560 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4561 if(!dest_conv_addr) {
4562 ERR("Out of memory\n");
4563 /* Continue without storing converted vertices */
4565 dest_conv = dest_conv_addr;
4569 * a) WINED3DRS_CLIPPING is enabled
4570 * b) WINED3DVOP_CLIP is passed
4572 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4573 static BOOL warned = FALSE;
4575 * The clipping code is not quite correct. Some things need
4576 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4577 * so disable clipping for now.
4578 * (The graphics in Half-Life are broken, and my processvertices
4579 * test crashes with IDirect3DDevice3)
4585 FIXME("Clipping is broken and disabled for now\n");
4587 } else doClip = FALSE;
4588 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4590 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4593 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4594 WINED3DTS_PROJECTION,
4596 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4597 WINED3DTS_WORLDMATRIX(0),
4600 TRACE("View mat:\n");
4601 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);
4602 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);
4603 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);
4604 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);
4606 TRACE("Proj mat:\n");
4607 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);
4608 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);
4609 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);
4610 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);
4612 TRACE("World mat:\n");
4613 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);
4614 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);
4615 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);
4616 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);
4618 /* Get the viewport */
4619 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4620 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4621 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4623 multiply_matrix(&mat,&view_mat,&world_mat);
4624 multiply_matrix(&mat,&proj_mat,&mat);
4626 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4628 for (i = 0; i < dwCount; i+= 1) {
4629 unsigned int tex_index;
4631 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4632 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4633 /* The position first */
4634 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
4635 const float *p = (const float *)(element->data + i * element->stride);
4637 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4639 /* Multiplication with world, view and projection matrix */
4640 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);
4641 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);
4642 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);
4643 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);
4645 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4647 /* WARNING: The following things are taken from d3d7 and were not yet checked
4648 * against d3d8 or d3d9!
4651 /* Clipping conditions: From msdn
4653 * A vertex is clipped if it does not match the following requirements
4657 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4659 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4660 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4665 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4666 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4669 /* "Normal" viewport transformation (not clipped)
4670 * 1) The values are divided by rhw
4671 * 2) The y axis is negative, so multiply it with -1
4672 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4673 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4674 * 4) Multiply x with Width/2 and add Width/2
4675 * 5) The same for the height
4676 * 6) Add the viewpoint X and Y to the 2D coordinates and
4677 * The minimum Z value to z
4678 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4680 * Well, basically it's simply a linear transformation into viewport
4692 z *= vp.MaxZ - vp.MinZ;
4694 x += vp.Width / 2 + vp.X;
4695 y += vp.Height / 2 + vp.Y;
4700 /* That vertex got clipped
4701 * Contrary to OpenGL it is not dropped completely, it just
4702 * undergoes a different calculation.
4704 TRACE("Vertex got clipped\n");
4711 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4712 * outside of the main vertex buffer memory. That needs some more
4717 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4720 ( (float *) dest_ptr)[0] = x;
4721 ( (float *) dest_ptr)[1] = y;
4722 ( (float *) dest_ptr)[2] = z;
4723 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4725 dest_ptr += 3 * sizeof(float);
4727 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4728 dest_ptr += sizeof(float);
4733 ( (float *) dest_conv)[0] = x * w;
4734 ( (float *) dest_conv)[1] = y * w;
4735 ( (float *) dest_conv)[2] = z * w;
4736 ( (float *) dest_conv)[3] = w;
4738 dest_conv += 3 * sizeof(float);
4740 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4741 dest_conv += sizeof(float);
4745 if (DestFVF & WINED3DFVF_PSIZE) {
4746 dest_ptr += sizeof(DWORD);
4747 if(dest_conv) dest_conv += sizeof(DWORD);
4749 if (DestFVF & WINED3DFVF_NORMAL) {
4750 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4751 const float *normal = (const float *)(element->data + i * element->stride);
4752 /* AFAIK this should go into the lighting information */
4753 FIXME("Didn't expect the destination to have a normal\n");
4754 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4756 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4760 if (DestFVF & WINED3DFVF_DIFFUSE) {
4761 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4762 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4764 static BOOL warned = FALSE;
4767 ERR("No diffuse color in source, but destination has one\n");
4771 *( (DWORD *) dest_ptr) = 0xffffffff;
4772 dest_ptr += sizeof(DWORD);
4775 *( (DWORD *) dest_conv) = 0xffffffff;
4776 dest_conv += sizeof(DWORD);
4780 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4782 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4783 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4784 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4785 dest_conv += sizeof(DWORD);
4790 if (DestFVF & WINED3DFVF_SPECULAR) {
4791 /* What's the color value in the feedback buffer? */
4792 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4793 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4795 static BOOL warned = FALSE;
4798 ERR("No specular color in source, but destination has one\n");
4802 *( (DWORD *) dest_ptr) = 0xFF000000;
4803 dest_ptr += sizeof(DWORD);
4806 *( (DWORD *) dest_conv) = 0xFF000000;
4807 dest_conv += sizeof(DWORD);
4811 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4813 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4814 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4815 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4816 dest_conv += sizeof(DWORD);
4821 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4822 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4823 const float *tex_coord = (const float *)(element->data + i * element->stride);
4825 ERR("No source texture, but destination requests one\n");
4826 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4827 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4830 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4832 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4839 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4840 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4841 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4842 dwCount * get_flexible_vertex_size(DestFVF),
4844 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4845 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4852 #undef copy_and_next
4854 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4855 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4858 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4859 struct wined3d_stream_info stream_info;
4860 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4861 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4864 ERR("Output vertex declaration not implemented yet\n");
4867 /* Need any context to write to the vbo. */
4868 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4870 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4871 * control the streamIsUP flag, thus restore it afterwards.
4873 This->stateBlock->streamIsUP = FALSE;
4874 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4875 This->stateBlock->streamIsUP = streamWasUP;
4877 if(vbo || SrcStartIndex) {
4879 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4880 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4882 * Also get the start index in, but only loop over all elements if there's something to add at all.
4884 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4886 struct wined3d_stream_info_element *e = &stream_info.elements[i];
4887 if (e->buffer_object)
4889 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
4890 e->buffer_object = 0;
4891 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
4893 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4894 vb->buffer_object = 0;
4897 if (e->data) e->data += e->stride * SrcStartIndex;
4901 return process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4902 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4906 * Get / Set Texture Stage States
4907 * TODO: Verify against dx9 definitions
4909 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4910 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4911 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4913 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4915 if (Stage >= MAX_TEXTURES) {
4916 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4920 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4921 This->updateStateBlock->textureState[Stage][Type] = Value;
4923 if (This->isRecordingState) {
4924 TRACE("Recording... not performing anything\n");
4928 /* Checked after the assignments to allow proper stateblock recording */
4929 if(oldValue == Value) {
4930 TRACE("App is setting the old value over, nothing to do\n");
4934 if(Stage > This->stateBlock->lowest_disabled_stage &&
4935 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4936 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4937 * Changes in other states are important on disabled stages too
4942 if(Type == WINED3DTSS_COLOROP) {
4945 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4946 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4947 * they have to be disabled
4949 * The current stage is dirtified below.
4951 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4952 TRACE("Additionally dirtifying stage %u\n", i);
4953 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4955 This->stateBlock->lowest_disabled_stage = Stage;
4956 TRACE("New lowest disabled: %u\n", Stage);
4957 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4958 /* Previously disabled stage enabled. Stages above it may need enabling
4959 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4960 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4962 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4965 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4966 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4969 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4970 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4972 This->stateBlock->lowest_disabled_stage = i;
4973 TRACE("New lowest disabled: %u\n", i);
4977 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4982 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4983 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4984 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4985 *pValue = This->updateStateBlock->textureState[Stage][Type];
4992 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4993 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4994 IWineD3DBaseTexture *oldTexture;
4996 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4998 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4999 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
5002 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
5003 ERR("Current stage overflows textures array (stage %d)\n", Stage);
5004 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
5007 oldTexture = This->updateStateBlock->textures[Stage];
5009 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
5010 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
5012 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
5013 return WINED3DERR_INVALIDCALL;
5016 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
5017 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
5019 This->updateStateBlock->changed.textures |= 1 << Stage;
5020 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
5021 This->updateStateBlock->textures[Stage] = pTexture;
5023 /* Handle recording of state blocks */
5024 if (This->isRecordingState) {
5025 TRACE("Recording... not performing anything\n");
5029 if(oldTexture == pTexture) {
5030 TRACE("App is setting the same texture again, nothing to do\n");
5034 /** NOTE: MSDN says that setTexture increases the reference count,
5035 * and that the application must set the texture back to null (or have a leaky application),
5036 * This means we should pass the refcount up to the parent
5037 *******************************/
5038 if (NULL != This->updateStateBlock->textures[Stage]) {
5039 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
5040 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
5041 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
5043 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
5045 if (!oldTexture || dimensions != IWineD3DBaseTexture_GetTextureDimensions(oldTexture))
5047 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
5050 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
5051 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
5052 * so the COLOROP and ALPHAOP have to be dirtified.
5054 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
5055 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
5057 if(bindCount == 1) {
5058 new->baseTexture.sampler = Stage;
5060 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
5064 if (NULL != oldTexture) {
5065 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
5066 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
5068 IWineD3DBaseTexture_Release(oldTexture);
5069 if(pTexture == NULL && Stage < MAX_TEXTURES) {
5070 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
5071 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
5074 if(bindCount && old->baseTexture.sampler == Stage) {
5076 /* Have to do a search for the other sampler(s) where the texture is bound to
5077 * Shouldn't happen as long as apps bind a texture only to one stage
5079 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
5080 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5081 if(This->updateStateBlock->textures[i] == oldTexture) {
5082 old->baseTexture.sampler = i;
5089 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
5094 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
5095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5097 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
5099 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
5100 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
5103 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
5104 ERR("Current stage overflows textures array (stage %d)\n", Stage);
5105 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
5108 *ppTexture=This->stateBlock->textures[Stage];
5110 IWineD3DBaseTexture_AddRef(*ppTexture);
5112 TRACE("(%p) : Returning %p\n", This, *ppTexture);
5120 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
5121 IWineD3DSurface **ppBackBuffer) {
5122 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5123 IWineD3DSwapChain *swapChain;
5126 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
5128 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5129 if (hr == WINED3D_OK) {
5130 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
5131 IWineD3DSwapChain_Release(swapChain);
5133 *ppBackBuffer = NULL;
5138 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
5139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5140 WARN("(%p) : stub, calling idirect3d for now\n", This);
5141 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
5144 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
5145 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5146 IWineD3DSwapChain *swapChain;
5149 if(iSwapChain > 0) {
5150 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5151 if (hr == WINED3D_OK) {
5152 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
5153 IWineD3DSwapChain_Release(swapChain);
5155 FIXME("(%p) Error getting display mode\n", This);
5158 /* Don't read the real display mode,
5159 but return the stored mode instead. X11 can't change the color
5160 depth, and some apps are pretty angry if they SetDisplayMode from
5161 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
5163 Also don't relay to the swapchain because with ddraw it's possible
5164 that there isn't a swapchain at all */
5165 pMode->Width = This->ddraw_width;
5166 pMode->Height = This->ddraw_height;
5167 pMode->Format = This->ddraw_format;
5168 pMode->RefreshRate = 0;
5176 * Stateblock related functions
5179 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
5180 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5181 IWineD3DStateBlock *stateblock;
5184 TRACE("(%p)\n", This);
5186 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
5188 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
5189 if (FAILED(hr)) return hr;
5191 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
5192 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
5193 This->isRecordingState = TRUE;
5195 TRACE("(%p) recording stateblock %p\n", This, stateblock);
5200 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
5201 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5203 IWineD3DStateBlockImpl *object = This->updateStateBlock;
5205 if (!This->isRecordingState) {
5206 WARN("(%p) not recording! returning error\n", This);
5207 *ppStateBlock = NULL;
5208 return WINED3DERR_INVALIDCALL;
5211 for (i = 0; i <= WINEHIGHEST_RENDER_STATE >> 5; ++i)
5213 DWORD map = object->changed.renderState[i];
5214 for (j = 0; map; map >>= 1, ++j)
5216 if (!(map & 1)) continue;
5218 object->contained_render_states[object->num_contained_render_states++] = (i << 5) | j;
5222 for (i = 0; i <= HIGHEST_TRANSFORMSTATE >> 5; ++i)
5224 DWORD map = object->changed.transform[i];
5225 for (j = 0; map; map >>= 1, ++j)
5227 if (!(map & 1)) continue;
5229 object->contained_transform_states[object->num_contained_transform_states++] = (i << 5) | j;
5232 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
5233 if(object->changed.vertexShaderConstantsF[i]) {
5234 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
5235 object->num_contained_vs_consts_f++;
5238 for(i = 0; i < MAX_CONST_I; i++) {
5239 if (object->changed.vertexShaderConstantsI & (1 << i))
5241 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
5242 object->num_contained_vs_consts_i++;
5245 for(i = 0; i < MAX_CONST_B; i++) {
5246 if (object->changed.vertexShaderConstantsB & (1 << i))
5248 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
5249 object->num_contained_vs_consts_b++;
5252 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
5254 if (object->changed.pixelShaderConstantsF[i])
5256 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
5257 ++object->num_contained_ps_consts_f;
5260 for(i = 0; i < MAX_CONST_I; i++) {
5261 if (object->changed.pixelShaderConstantsI & (1 << i))
5263 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
5264 object->num_contained_ps_consts_i++;
5267 for(i = 0; i < MAX_CONST_B; i++) {
5268 if (object->changed.pixelShaderConstantsB & (1 << i))
5270 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
5271 object->num_contained_ps_consts_b++;
5274 for(i = 0; i < MAX_TEXTURES; i++) {
5275 DWORD map = object->changed.textureState[i];
5277 for(j = 0; map; map >>= 1, ++j)
5279 if (!(map & 1)) continue;
5281 object->contained_tss_states[object->num_contained_tss_states].stage = i;
5282 object->contained_tss_states[object->num_contained_tss_states].state = j;
5283 ++object->num_contained_tss_states;
5286 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
5287 DWORD map = object->changed.samplerState[i];
5289 for (j = 0; map; map >>= 1, ++j)
5291 if (!(map & 1)) continue;
5293 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
5294 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
5295 ++object->num_contained_sampler_states;
5299 *ppStateBlock = (IWineD3DStateBlock*) object;
5300 This->isRecordingState = FALSE;
5301 This->updateStateBlock = This->stateBlock;
5302 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5303 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5304 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5309 * Scene related functions
5311 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5312 /* At the moment we have no need for any functionality at the beginning
5314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5315 TRACE("(%p)\n", This);
5318 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
5319 return WINED3DERR_INVALIDCALL;
5321 This->inScene = TRUE;
5325 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5326 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5327 TRACE("(%p)\n", This);
5329 if(!This->inScene) {
5330 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
5331 return WINED3DERR_INVALIDCALL;
5334 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5335 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5337 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
5341 This->inScene = FALSE;
5345 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5346 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5347 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5348 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5349 IWineD3DSwapChain *swapChain = NULL;
5351 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5353 TRACE("(%p) Presenting the frame\n", This);
5355 for(i = 0 ; i < swapchains ; i ++) {
5357 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
5358 TRACE("presentinng chain %d, %p\n", i, swapChain);
5359 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5360 IWineD3DSwapChain_Release(swapChain);
5366 /* Not called from the VTable (internal subroutine) */
5367 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
5368 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
5369 float Z, DWORD Stencil) {
5370 GLbitfield glMask = 0;
5372 WINED3DRECT curRect;
5374 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
5375 UINT drawable_width, drawable_height;
5376 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
5377 IWineD3DSwapChainImpl *swapchain = NULL;
5379 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5380 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5381 * for the cleared parts, and the untouched parts.
5383 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5384 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5385 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5386 * checking all this if the dest surface is in the drawable anyway.
5388 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5390 if(vp->X != 0 || vp->Y != 0 ||
5391 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5392 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5395 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5396 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5397 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5398 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5399 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5402 if(Count > 0 && pRects && (
5403 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5404 pRects[0].x2 < target->currentDesc.Width ||
5405 pRects[0].y2 < target->currentDesc.Height)) {
5406 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5413 target->get_drawable_size(target, &drawable_width, &drawable_height);
5415 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5418 /* Only set the values up once, as they are not changing */
5419 if (Flags & WINED3DCLEAR_STENCIL) {
5420 glClearStencil(Stencil);
5421 checkGLcall("glClearStencil");
5422 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5423 glStencilMask(0xFFFFFFFF);
5426 if (Flags & WINED3DCLEAR_ZBUFFER) {
5427 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5428 glDepthMask(GL_TRUE);
5430 checkGLcall("glClearDepth");
5431 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5432 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5434 if (vp->X != 0 || vp->Y != 0 ||
5435 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5436 surface_load_ds_location(This->stencilBufferTarget, location);
5438 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5439 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5440 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5441 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5442 surface_load_ds_location(This->stencilBufferTarget, location);
5444 else if (Count > 0 && pRects && (
5445 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5446 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5447 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5448 surface_load_ds_location(This->stencilBufferTarget, location);
5452 if (Flags & WINED3DCLEAR_TARGET) {
5453 TRACE("Clearing screen with glClear to color %x\n", Color);
5454 glClearColor(D3DCOLOR_R(Color),
5458 checkGLcall("glClearColor");
5460 /* Clear ALL colors! */
5461 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5462 glMask = glMask | GL_COLOR_BUFFER_BIT;
5465 vp_rect.left = vp->X;
5466 vp_rect.top = vp->Y;
5467 vp_rect.right = vp->X + vp->Width;
5468 vp_rect.bottom = vp->Y + vp->Height;
5469 if (!(Count > 0 && pRects)) {
5470 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5471 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5473 if(This->render_offscreen) {
5474 glScissor(vp_rect.left, vp_rect.top,
5475 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5477 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5478 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5480 checkGLcall("glScissor");
5482 checkGLcall("glClear");
5484 /* Now process each rect in turn */
5485 for (i = 0; i < Count; i++) {
5486 /* Note gl uses lower left, width/height */
5487 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5488 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5489 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5491 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5492 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5493 curRect.x1, (target->currentDesc.Height - curRect.y2),
5494 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5496 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5497 * The rectangle is not cleared, no error is returned, but further rectanlges are
5498 * still cleared if they are valid
5500 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5501 TRACE("Rectangle with negative dimensions, ignoring\n");
5505 if(This->render_offscreen) {
5506 glScissor(curRect.x1, curRect.y1,
5507 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5509 glScissor(curRect.x1, drawable_height - curRect.y2,
5510 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5512 checkGLcall("glScissor");
5515 checkGLcall("glClear");
5519 /* Restore the old values (why..?) */
5520 if (Flags & WINED3DCLEAR_STENCIL) {
5521 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5523 if (Flags & WINED3DCLEAR_TARGET) {
5524 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5525 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5526 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5527 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5528 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5530 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5531 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5533 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5535 if (Flags & WINED3DCLEAR_ZBUFFER) {
5536 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5537 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5538 surface_modify_ds_location(This->stencilBufferTarget, location);
5543 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5544 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5547 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5553 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5554 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5555 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5556 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5558 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5559 Count, pRects, Flags, Color, Z, Stencil);
5561 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5562 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5563 /* TODO: What about depth stencil buffers without stencil bits? */
5564 return WINED3DERR_INVALIDCALL;
5567 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5574 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
5575 WINED3DPRIMITIVETYPE primitive_type)
5577 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5579 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
5581 This->updateStateBlock->changed.primitive_type = TRUE;
5582 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
5585 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
5586 WINED3DPRIMITIVETYPE *primitive_type)
5588 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5590 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
5592 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
5594 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
5597 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
5599 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5601 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
5603 if(!This->stateBlock->vertexDecl) {
5604 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5605 return WINED3DERR_INVALIDCALL;
5608 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5609 if(This->stateBlock->streamIsUP) {
5610 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5611 This->stateBlock->streamIsUP = FALSE;
5614 if(This->stateBlock->loadBaseVertexIndex != 0) {
5615 This->stateBlock->loadBaseVertexIndex = 0;
5616 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5618 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5619 drawPrimitive(iface, vertex_count, 0/* NumVertices */, StartVertex /* start_idx */,
5620 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5624 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5625 UINT minIndex, UINT NumVertices, UINT startIndex, UINT index_count)
5627 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5629 IWineD3DBuffer *pIB;
5632 pIB = This->stateBlock->pIndexData;
5634 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5635 * without an index buffer set. (The first time at least...)
5636 * D3D8 simply dies, but I doubt it can do much harm to return
5637 * D3DERR_INVALIDCALL there as well. */
5638 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5639 return WINED3DERR_INVALIDCALL;
5642 if(!This->stateBlock->vertexDecl) {
5643 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5644 return WINED3DERR_INVALIDCALL;
5647 if(This->stateBlock->streamIsUP) {
5648 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5649 This->stateBlock->streamIsUP = FALSE;
5651 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
5653 TRACE("(%p) : min %u, vertex count %u, startIdx %u, index count %u\n",
5654 This, minIndex, NumVertices, startIndex, index_count);
5656 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
5662 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5663 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5664 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5667 drawPrimitive(iface, index_count, NumVertices, startIndex, idxStride,
5668 vbo ? NULL : ((struct wined3d_buffer *) pIB)->resource.allocatedMemory, minIndex);
5673 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
5674 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5676 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5679 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
5680 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
5682 if(!This->stateBlock->vertexDecl) {
5683 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5684 return WINED3DERR_INVALIDCALL;
5687 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5688 vb = This->stateBlock->streamSource[0];
5689 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5690 if (vb) IWineD3DBuffer_Release(vb);
5691 This->stateBlock->streamOffset[0] = 0;
5692 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5693 This->stateBlock->streamIsUP = TRUE;
5694 This->stateBlock->loadBaseVertexIndex = 0;
5696 /* TODO: Only mark dirty if drawing from a different UP address */
5697 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5699 drawPrimitive(iface, vertex_count, 0 /* NumVertices */, 0 /* start_idx */,
5700 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5702 /* MSDN specifies stream zero settings must be set to NULL */
5703 This->stateBlock->streamStride[0] = 0;
5704 This->stateBlock->streamSource[0] = NULL;
5706 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5707 * the new stream sources or use UP drawing again
5712 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, UINT MinVertexIndex,
5713 UINT NumVertices, UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
5714 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5717 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5721 TRACE("(%p) : MinVtxIdx %u, NumVIdx %u, index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u\n",
5722 This, MinVertexIndex, NumVertices, index_count, pIndexData,
5723 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5725 if(!This->stateBlock->vertexDecl) {
5726 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5727 return WINED3DERR_INVALIDCALL;
5730 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
5736 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5737 vb = This->stateBlock->streamSource[0];
5738 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5739 if (vb) IWineD3DBuffer_Release(vb);
5740 This->stateBlock->streamIsUP = TRUE;
5741 This->stateBlock->streamOffset[0] = 0;
5742 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5744 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5745 This->stateBlock->baseVertexIndex = 0;
5746 This->stateBlock->loadBaseVertexIndex = 0;
5747 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5748 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5749 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5751 drawPrimitive(iface, index_count, NumVertices, 0 /* start_idx */,
5752 idxStride, pIndexData, MinVertexIndex);
5754 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5755 This->stateBlock->streamSource[0] = NULL;
5756 This->stateBlock->streamStride[0] = 0;
5757 ib = This->stateBlock->pIndexData;
5759 IWineD3DBuffer_Release(ib);
5760 This->stateBlock->pIndexData = NULL;
5762 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5763 * SetStreamSource to specify a vertex buffer
5769 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5770 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
5772 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5774 /* Mark the state dirty until we have nicer tracking
5775 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5778 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5779 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5780 This->stateBlock->baseVertexIndex = 0;
5781 This->up_strided = DrawPrimStrideData;
5782 drawPrimitive(iface, vertex_count, 0, 0, 0, NULL, 0);
5783 This->up_strided = NULL;
5787 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5788 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
5789 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
5791 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5792 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5794 /* Mark the state dirty until we have nicer tracking
5795 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5798 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5799 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5800 This->stateBlock->streamIsUP = TRUE;
5801 This->stateBlock->baseVertexIndex = 0;
5802 This->up_strided = DrawPrimStrideData;
5803 drawPrimitive(iface, vertex_count, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData, 0 /* minindex */);
5804 This->up_strided = NULL;
5808 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5809 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5810 * not callable by the app directly no parameter validation checks are needed here.
5812 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5813 WINED3DLOCKED_BOX src;
5814 WINED3DLOCKED_BOX dst;
5816 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5818 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5819 * dirtification to improve loading performance.
5821 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5822 if(FAILED(hr)) return hr;
5823 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5825 IWineD3DVolume_UnlockBox(pSourceVolume);
5829 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5831 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5833 IWineD3DVolume_UnlockBox(pSourceVolume);
5835 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5840 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5841 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5842 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5843 HRESULT hr = WINED3D_OK;
5844 WINED3DRESOURCETYPE sourceType;
5845 WINED3DRESOURCETYPE destinationType;
5848 /* TODO: think about moving the code into IWineD3DBaseTexture */
5850 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5852 /* verify that the source and destination textures aren't NULL */
5853 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5854 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5855 This, pSourceTexture, pDestinationTexture);
5856 hr = WINED3DERR_INVALIDCALL;
5859 if (pSourceTexture == pDestinationTexture) {
5860 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5861 This, pSourceTexture, pDestinationTexture);
5862 hr = WINED3DERR_INVALIDCALL;
5864 /* Verify that the source and destination textures are the same type */
5865 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5866 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5868 if (sourceType != destinationType) {
5869 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5871 hr = WINED3DERR_INVALIDCALL;
5874 /* check that both textures have the identical numbers of levels */
5875 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5876 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5877 hr = WINED3DERR_INVALIDCALL;
5880 if (WINED3D_OK == hr) {
5881 IWineD3DBaseTextureImpl *pDestImpl = (IWineD3DBaseTextureImpl *) pDestinationTexture;
5883 /* Make sure that the destination texture is loaded */
5884 pDestImpl->baseTexture.internal_preload(pDestinationTexture, SRGB_RGB);
5886 /* Update every surface level of the texture */
5887 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5889 switch (sourceType) {
5890 case WINED3DRTYPE_TEXTURE:
5892 IWineD3DSurface *srcSurface;
5893 IWineD3DSurface *destSurface;
5895 for (i = 0 ; i < levels ; ++i) {
5896 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5897 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5898 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5899 IWineD3DSurface_Release(srcSurface);
5900 IWineD3DSurface_Release(destSurface);
5901 if (WINED3D_OK != hr) {
5902 WARN("(%p) : Call to update surface failed\n", This);
5908 case WINED3DRTYPE_CUBETEXTURE:
5910 IWineD3DSurface *srcSurface;
5911 IWineD3DSurface *destSurface;
5912 WINED3DCUBEMAP_FACES faceType;
5914 for (i = 0 ; i < levels ; ++i) {
5915 /* Update each cube face */
5916 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5917 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5918 if (WINED3D_OK != hr) {
5919 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5921 TRACE("Got srcSurface %p\n", srcSurface);
5923 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5924 if (WINED3D_OK != hr) {
5925 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5927 TRACE("Got desrSurface %p\n", destSurface);
5929 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5930 IWineD3DSurface_Release(srcSurface);
5931 IWineD3DSurface_Release(destSurface);
5932 if (WINED3D_OK != hr) {
5933 WARN("(%p) : Call to update surface failed\n", This);
5941 case WINED3DRTYPE_VOLUMETEXTURE:
5943 IWineD3DVolume *srcVolume = NULL;
5944 IWineD3DVolume *destVolume = NULL;
5946 for (i = 0 ; i < levels ; ++i) {
5947 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5948 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5949 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5950 IWineD3DVolume_Release(srcVolume);
5951 IWineD3DVolume_Release(destVolume);
5952 if (WINED3D_OK != hr) {
5953 WARN("(%p) : Call to update volume failed\n", This);
5961 FIXME("(%p) : Unsupported source and destination type\n", This);
5962 hr = WINED3DERR_INVALIDCALL;
5969 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5970 IWineD3DSwapChain *swapChain;
5972 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5973 if(hr == WINED3D_OK) {
5974 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5975 IWineD3DSwapChain_Release(swapChain);
5980 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5981 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5982 IWineD3DBaseTextureImpl *texture;
5985 TRACE("(%p) : %p\n", This, pNumPasses);
5987 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5988 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5989 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5990 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5992 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5993 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5994 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5997 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5998 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
6000 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
6001 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
6004 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
6005 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
6008 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
6009 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
6010 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
6015 /* return a sensible default */
6018 TRACE("returning D3D_OK\n");
6022 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
6026 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
6027 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
6028 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8
6029 || texture->resource.format_desc->format == WINED3DFMT_A8P8))
6031 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
6036 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
6037 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6040 PALETTEENTRY **palettes;
6042 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6044 if (PaletteNumber >= MAX_PALETTES) {
6045 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6046 return WINED3DERR_INVALIDCALL;
6049 if (PaletteNumber >= This->NumberOfPalettes) {
6050 NewSize = This->NumberOfPalettes;
6053 } while(PaletteNumber >= NewSize);
6054 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
6056 ERR("Out of memory!\n");
6057 return E_OUTOFMEMORY;
6059 This->palettes = palettes;
6060 This->NumberOfPalettes = NewSize;
6063 if (!This->palettes[PaletteNumber]) {
6064 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
6065 if (!This->palettes[PaletteNumber]) {
6066 ERR("Out of memory!\n");
6067 return E_OUTOFMEMORY;
6071 for (j = 0; j < 256; ++j) {
6072 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
6073 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
6074 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
6075 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
6077 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
6078 TRACE("(%p) : returning\n", This);
6082 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
6083 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6085 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6086 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
6087 /* What happens in such situation isn't documented; Native seems to silently abort
6088 on such conditions. Return Invalid Call. */
6089 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
6090 return WINED3DERR_INVALIDCALL;
6092 for (j = 0; j < 256; ++j) {
6093 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
6094 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
6095 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
6096 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
6098 TRACE("(%p) : returning\n", This);
6102 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
6103 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6104 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6105 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
6106 (tested with reference rasterizer). Return Invalid Call. */
6107 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
6108 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
6109 return WINED3DERR_INVALIDCALL;
6111 /*TODO: stateblocks */
6112 if (This->currentPalette != PaletteNumber) {
6113 This->currentPalette = PaletteNumber;
6114 dirtify_p8_texture_samplers(This);
6116 TRACE("(%p) : returning\n", This);
6120 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
6121 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6122 if (PaletteNumber == NULL) {
6123 WARN("(%p) : returning Invalid Call\n", This);
6124 return WINED3DERR_INVALIDCALL;
6126 /*TODO: stateblocks */
6127 *PaletteNumber = This->currentPalette;
6128 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
6132 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
6133 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6137 FIXME("(%p) : stub\n", This);
6141 This->softwareVertexProcessing = bSoftware;
6146 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
6147 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6151 FIXME("(%p) : stub\n", This);
6154 return This->softwareVertexProcessing;
6158 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
6159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6160 IWineD3DSwapChain *swapChain;
6163 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
6165 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
6166 if(hr == WINED3D_OK){
6167 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
6168 IWineD3DSwapChain_Release(swapChain);
6170 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
6176 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
6177 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6179 if(nSegments != 0.0f) {
6182 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
6189 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
6190 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6194 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
6200 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
6201 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6202 /** TODO: remove casts to IWineD3DSurfaceImpl
6203 * NOTE: move code to surface to accomplish this
6204 ****************************************/
6205 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
6206 int srcWidth, srcHeight;
6207 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
6208 WINED3DFORMAT destFormat, srcFormat;
6210 int srcLeft, destLeft, destTop;
6211 WINED3DPOOL srcPool, destPool;
6213 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
6214 glDescriptor *glDescription = NULL;
6215 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
6219 CONVERT_TYPES convert = NO_CONVERSION;
6221 WINED3DSURFACE_DESC winedesc;
6223 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
6224 memset(&winedesc, 0, sizeof(winedesc));
6225 winedesc.Width = &srcSurfaceWidth;
6226 winedesc.Height = &srcSurfaceHeight;
6227 winedesc.Pool = &srcPool;
6228 winedesc.Format = &srcFormat;
6230 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6232 winedesc.Width = &destSurfaceWidth;
6233 winedesc.Height = &destSurfaceHeight;
6234 winedesc.Pool = &destPool;
6235 winedesc.Format = &destFormat;
6236 winedesc.Size = &destSize;
6238 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6240 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
6241 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
6242 return WINED3DERR_INVALIDCALL;
6245 /* This call loads the opengl surface directly, instead of copying the surface to the
6246 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
6247 * copy in sysmem and use regular surface loading.
6249 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
6250 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
6251 if(convert != NO_CONVERSION) {
6252 return IWineD3DSurface_BltFast(pDestinationSurface,
6253 pDestPoint ? pDestPoint->x : 0,
6254 pDestPoint ? pDestPoint->y : 0,
6255 pSourceSurface, pSourceRect, 0);
6258 if (destFormat == WINED3DFMT_UNKNOWN) {
6259 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6260 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6262 /* Get the update surface description */
6263 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6266 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6269 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6270 checkGLcall("glActiveTextureARB");
6273 /* Make sure the surface is loaded and up to date */
6274 surface_internal_preload(pDestinationSurface, SRGB_RGB);
6275 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
6277 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
6279 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
6280 dst_format_desc = ((IWineD3DSurfaceImpl *)pDestinationSurface)->resource.format_desc;
6282 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6283 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6284 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
6285 srcLeft = pSourceRect ? pSourceRect->left : 0;
6286 destLeft = pDestPoint ? pDestPoint->x : 0;
6287 destTop = pDestPoint ? pDestPoint->y : 0;
6290 /* This function doesn't support compressed textures
6291 the pitch is just bytesPerPixel * width */
6292 if(srcWidth != srcSurfaceWidth || srcLeft ){
6293 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
6294 offset += srcLeft * src_format_desc->byte_count;
6295 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6297 /* TODO DXT formats */
6299 if(pSourceRect != NULL && pSourceRect->top != 0){
6300 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
6302 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
6303 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
6304 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
6307 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6309 /* need to lock the surface to get the data */
6310 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6315 /* TODO: Cube and volume support */
6317 /* not a whole row so we have to do it a line at a time */
6320 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
6321 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6323 for (j = destTop; j < (srcHeight + destTop); ++j)
6325 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, j,
6326 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
6330 } else { /* Full width, so just write out the whole texture */
6331 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6333 if (WINED3DFMT_DXT1 == destFormat ||
6334 WINED3DFMT_DXT2 == destFormat ||
6335 WINED3DFMT_DXT3 == destFormat ||
6336 WINED3DFMT_DXT4 == destFormat ||
6337 WINED3DFMT_DXT5 == destFormat) {
6338 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6339 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6340 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
6341 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6342 } if (destFormat != srcFormat) {
6343 FIXME("Updating mixed format compressed texture is not curretly support\n");
6345 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
6346 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
6349 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6354 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
6355 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
6358 checkGLcall("glTexSubImage2D");
6362 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
6363 sampler = This->rev_tex_unit_map[0];
6364 if (sampler != -1) {
6365 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6371 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6372 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6373 struct WineD3DRectPatch *patch;
6374 GLenum old_primitive_type;
6378 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6380 if(!(Handle || pRectPatchInfo)) {
6381 /* TODO: Write a test for the return value, thus the FIXME */
6382 FIXME("Both Handle and pRectPatchInfo are NULL\n");
6383 return WINED3DERR_INVALIDCALL;
6387 i = PATCHMAP_HASHFUNC(Handle);
6389 LIST_FOR_EACH(e, &This->patches[i]) {
6390 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6391 if(patch->Handle == Handle) {
6398 TRACE("Patch does not exist. Creating a new one\n");
6399 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6400 patch->Handle = Handle;
6401 list_add_head(&This->patches[i], &patch->entry);
6403 TRACE("Found existing patch %p\n", patch);
6406 /* Since opengl does not load tesselated vertex attributes into numbered vertex
6407 * attributes we have to tesselate, read back, and draw. This needs a patch
6408 * management structure instance. Create one.
6410 * A possible improvement is to check if a vertex shader is used, and if not directly
6413 FIXME("Drawing an uncached patch. This is slow\n");
6414 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6417 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
6418 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
6419 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
6421 TRACE("Tesselation density or patch info changed, retesselating\n");
6423 if(pRectPatchInfo) {
6424 patch->RectPatchInfo = *pRectPatchInfo;
6426 patch->numSegs[0] = pNumSegs[0];
6427 patch->numSegs[1] = pNumSegs[1];
6428 patch->numSegs[2] = pNumSegs[2];
6429 patch->numSegs[3] = pNumSegs[3];
6431 hr = tesselate_rectpatch(This, patch);
6433 WARN("Patch tesselation failed\n");
6435 /* Do not release the handle to store the params of the patch */
6437 HeapFree(GetProcessHeap(), 0, patch);
6443 This->currentPatch = patch;
6444 old_primitive_type = This->stateBlock->gl_primitive_type;
6445 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
6446 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
6447 This->stateBlock->gl_primitive_type = old_primitive_type;
6448 This->currentPatch = NULL;
6450 /* Destroy uncached patches */
6452 HeapFree(GetProcessHeap(), 0, patch->mem);
6453 HeapFree(GetProcessHeap(), 0, patch);
6458 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6459 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6460 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6461 FIXME("(%p) : Stub\n", This);
6465 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6466 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6468 struct WineD3DRectPatch *patch;
6470 TRACE("(%p) Handle(%d)\n", This, Handle);
6472 i = PATCHMAP_HASHFUNC(Handle);
6473 LIST_FOR_EACH(e, &This->patches[i]) {
6474 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6475 if(patch->Handle == Handle) {
6476 TRACE("Deleting patch %p\n", patch);
6477 list_remove(&patch->entry);
6478 HeapFree(GetProcessHeap(), 0, patch->mem);
6479 HeapFree(GetProcessHeap(), 0, patch);
6484 /* TODO: Write a test for the return value */
6485 FIXME("Attempt to destroy nonexistent patch\n");
6486 return WINED3DERR_INVALIDCALL;
6489 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6491 IWineD3DSwapChain *swapchain;
6493 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6494 if (SUCCEEDED(hr)) {
6495 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6502 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
6503 const WINED3DRECT *rect, const float color[4])
6505 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6506 IWineD3DSwapChain *swapchain;
6508 swapchain = get_swapchain(surface);
6512 TRACE("Surface %p is onscreen\n", surface);
6514 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6516 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6517 buffer = surface_get_gl_buffer(surface, swapchain);
6518 glDrawBuffer(buffer);
6519 checkGLcall("glDrawBuffer()");
6521 TRACE("Surface %p is offscreen\n", surface);
6523 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6525 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6526 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6527 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6528 checkGLcall("glFramebufferRenderbufferEXT");
6532 glEnable(GL_SCISSOR_TEST);
6534 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6536 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6537 rect->x2 - rect->x1, rect->y2 - rect->y1);
6539 checkGLcall("glScissor");
6540 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6542 glDisable(GL_SCISSOR_TEST);
6544 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6546 glDisable(GL_BLEND);
6547 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6549 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6550 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6552 glClearColor(color[0], color[1], color[2], color[3]);
6553 glClear(GL_COLOR_BUFFER_BIT);
6554 checkGLcall("glClear");
6556 if (This->activeContext->current_fbo) {
6557 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6559 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6560 checkGLcall("glBindFramebuffer()");
6563 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6564 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6565 glDrawBuffer(GL_BACK);
6566 checkGLcall("glDrawBuffer()");
6572 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6573 unsigned int r, g, b, a;
6576 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6577 destfmt == WINED3DFMT_R8G8B8)
6580 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6582 a = (color & 0xff000000) >> 24;
6583 r = (color & 0x00ff0000) >> 16;
6584 g = (color & 0x0000ff00) >> 8;
6585 b = (color & 0x000000ff) >> 0;
6589 case WINED3DFMT_R5G6B5:
6590 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6597 TRACE("Returning %08x\n", ret);
6600 case WINED3DFMT_X1R5G5B5:
6601 case WINED3DFMT_A1R5G5B5:
6610 TRACE("Returning %08x\n", ret);
6613 case WINED3DFMT_A8_UNORM:
6614 TRACE("Returning %08x\n", a);
6617 case WINED3DFMT_X4R4G4B4:
6618 case WINED3DFMT_A4R4G4B4:
6627 TRACE("Returning %08x\n", ret);
6630 case WINED3DFMT_R3G3B2:
6637 TRACE("Returning %08x\n", ret);
6640 case WINED3DFMT_X8B8G8R8:
6641 case WINED3DFMT_R8G8B8A8_UNORM:
6646 TRACE("Returning %08x\n", ret);
6649 case WINED3DFMT_A2R10G10B10:
6651 r = (r * 1024) / 256;
6652 g = (g * 1024) / 256;
6653 b = (b * 1024) / 256;
6658 TRACE("Returning %08x\n", ret);
6661 case WINED3DFMT_R10G10B10A2_UNORM:
6663 r = (r * 1024) / 256;
6664 g = (g * 1024) / 256;
6665 b = (b * 1024) / 256;
6670 TRACE("Returning %08x\n", ret);
6674 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6679 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6681 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6683 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6685 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6686 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6687 return WINED3DERR_INVALIDCALL;
6690 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6691 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
6692 color_fill_fbo(iface, pSurface, pRect, c);
6695 /* Just forward this to the DirectDraw blitting engine */
6696 memset(&BltFx, 0, sizeof(BltFx));
6697 BltFx.dwSize = sizeof(BltFx);
6698 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
6699 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6700 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6704 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
6705 IWineD3DRendertargetView *rendertarget_view, const float color[4])
6707 IWineD3DResource *resource;
6708 IWineD3DSurface *surface;
6711 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
6714 ERR("Failed to get resource, hr %#x\n", hr);
6718 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
6720 FIXME("Only supported on surface resources\n");
6721 IWineD3DResource_Release(resource);
6725 surface = (IWineD3DSurface *)resource;
6727 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6729 color_fill_fbo(iface, surface, NULL, color);
6736 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
6738 c = ((DWORD)(color[2] * 255.0));
6739 c |= ((DWORD)(color[1] * 255.0)) << 8;
6740 c |= ((DWORD)(color[0] * 255.0)) << 16;
6741 c |= ((DWORD)(color[3] * 255.0)) << 24;
6743 /* Just forward this to the DirectDraw blitting engine */
6744 memset(&BltFx, 0, sizeof(BltFx));
6745 BltFx.dwSize = sizeof(BltFx);
6746 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
6747 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6750 ERR("Blt failed, hr %#x\n", hr);
6754 IWineD3DResource_Release(resource);
6757 /* rendertarget and depth stencil functions */
6758 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6759 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6761 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6762 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6763 return WINED3DERR_INVALIDCALL;
6766 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6767 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6768 /* Note inc ref on returned surface */
6769 if(*ppRenderTarget != NULL)
6770 IWineD3DSurface_AddRef(*ppRenderTarget);
6774 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6775 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6776 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6777 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6778 IWineD3DSwapChainImpl *Swapchain;
6781 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6783 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6784 if(hr != WINED3D_OK) {
6785 ERR("Can't get the swapchain\n");
6789 /* Make sure to release the swapchain */
6790 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6792 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6793 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6794 return WINED3DERR_INVALIDCALL;
6796 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6797 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6798 return WINED3DERR_INVALIDCALL;
6801 if(Swapchain->frontBuffer != Front) {
6802 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6804 if(Swapchain->frontBuffer)
6806 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6807 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
6809 Swapchain->frontBuffer = Front;
6811 if(Swapchain->frontBuffer) {
6812 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6813 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
6817 if(Back && !Swapchain->backBuffer) {
6818 /* We need memory for the back buffer array - only one back buffer this way */
6819 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6820 if(!Swapchain->backBuffer) {
6821 ERR("Out of memory\n");
6822 return E_OUTOFMEMORY;
6826 if(Swapchain->backBuffer[0] != Back) {
6827 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6829 /* What to do about the context here in the case of multithreading? Not sure.
6830 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6833 if(!Swapchain->backBuffer[0]) {
6834 /* GL was told to draw to the front buffer at creation,
6837 glDrawBuffer(GL_BACK);
6838 checkGLcall("glDrawBuffer(GL_BACK)");
6839 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6840 Swapchain->presentParms.BackBufferCount = 1;
6842 /* That makes problems - disable for now */
6843 /* glDrawBuffer(GL_FRONT); */
6844 checkGLcall("glDrawBuffer(GL_FRONT)");
6845 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6846 Swapchain->presentParms.BackBufferCount = 0;
6850 if(Swapchain->backBuffer[0])
6852 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6853 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
6855 Swapchain->backBuffer[0] = Back;
6857 if(Swapchain->backBuffer[0]) {
6858 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6859 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
6861 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6862 Swapchain->backBuffer = NULL;
6870 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6871 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6872 *ppZStencilSurface = This->stencilBufferTarget;
6873 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6875 if(*ppZStencilSurface != NULL) {
6876 /* Note inc ref on returned surface */
6877 IWineD3DSurface_AddRef(*ppZStencilSurface);
6880 return WINED3DERR_NOTFOUND;
6884 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6885 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6887 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6888 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6889 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6891 POINT offset = {0, 0};
6893 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6894 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6895 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6896 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6899 case WINED3DTEXF_LINEAR:
6900 gl_filter = GL_LINEAR;
6904 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6905 case WINED3DTEXF_NONE:
6906 case WINED3DTEXF_POINT:
6907 gl_filter = GL_NEAREST;
6911 /* Attach src surface to src fbo */
6912 src_swapchain = get_swapchain(src_surface);
6913 if (src_swapchain) {
6914 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6916 TRACE("Source surface %p is onscreen\n", src_surface);
6917 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6918 /* Make sure the drawable is up to date. In the offscreen case
6919 * attach_surface_fbo() implicitly takes care of this. */
6920 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6922 if(buffer == GL_FRONT) {
6925 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6926 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6927 h = windowsize.bottom - windowsize.top;
6928 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6929 src_rect->y1 = offset.y + h - src_rect->y1;
6930 src_rect->y2 = offset.y + h - src_rect->y2;
6932 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6933 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6937 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6938 glReadBuffer(buffer);
6939 checkGLcall("glReadBuffer()");
6941 TRACE("Source surface %p is offscreen\n", src_surface);
6943 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6944 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6945 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6946 checkGLcall("glReadBuffer()");
6947 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6948 checkGLcall("glFramebufferRenderbufferEXT");
6952 /* Attach dst surface to dst fbo */
6953 dst_swapchain = get_swapchain(dst_surface);
6954 if (dst_swapchain) {
6955 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6957 TRACE("Destination surface %p is onscreen\n", dst_surface);
6958 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6959 /* Make sure the drawable is up to date. In the offscreen case
6960 * attach_surface_fbo() implicitly takes care of this. */
6961 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6963 if(buffer == GL_FRONT) {
6966 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6967 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6968 h = windowsize.bottom - windowsize.top;
6969 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6970 dst_rect->y1 = offset.y + h - dst_rect->y1;
6971 dst_rect->y2 = offset.y + h - dst_rect->y2;
6973 /* Screen coords = window coords, surface height = window height */
6974 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6975 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6979 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6980 glDrawBuffer(buffer);
6981 checkGLcall("glDrawBuffer()");
6983 TRACE("Destination surface %p is offscreen\n", dst_surface);
6985 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6986 if(!src_swapchain) {
6987 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6991 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6992 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6993 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6994 checkGLcall("glDrawBuffer()");
6995 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6996 checkGLcall("glFramebufferRenderbufferEXT");
6998 glDisable(GL_SCISSOR_TEST);
6999 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
7002 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
7003 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
7004 checkGLcall("glBlitFramebuffer()");
7006 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
7007 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
7008 checkGLcall("glBlitFramebuffer()");
7011 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
7013 if (This->activeContext->current_fbo) {
7014 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
7016 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
7017 checkGLcall("glBindFramebuffer()");
7020 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
7021 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
7022 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
7023 glDrawBuffer(GL_BACK);
7024 checkGLcall("glDrawBuffer()");
7029 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
7030 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7031 WINED3DVIEWPORT viewport;
7033 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
7035 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
7036 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
7037 This, RenderTargetIndex, GL_LIMITS(buffers));
7038 return WINED3DERR_INVALIDCALL;
7041 /* MSDN says that null disables the render target
7042 but a device must always be associated with a render target
7043 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
7045 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
7046 FIXME("Trying to set render target 0 to NULL\n");
7047 return WINED3DERR_INVALIDCALL;
7049 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
7050 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);
7051 return WINED3DERR_INVALIDCALL;
7054 /* If we are trying to set what we already have, don't bother */
7055 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
7056 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7059 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
7060 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
7061 This->render_targets[RenderTargetIndex] = pRenderTarget;
7063 /* Render target 0 is special */
7064 if(RenderTargetIndex == 0) {
7065 /* Finally, reset the viewport as the MSDN states. */
7066 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
7067 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
7070 viewport.MaxZ = 1.0f;
7071 viewport.MinZ = 0.0f;
7072 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
7073 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
7074 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
7076 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
7081 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
7082 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7083 HRESULT hr = WINED3D_OK;
7084 IWineD3DSurface *tmp;
7086 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
7088 if (pNewZStencil == This->stencilBufferTarget) {
7089 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7091 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
7092 * depending on the renter target implementation being used.
7093 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
7094 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7095 * stencil buffer and incur an extra memory overhead
7096 ******************************************************/
7098 if (This->stencilBufferTarget) {
7099 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
7100 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
7101 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
7103 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
7104 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
7105 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
7109 tmp = This->stencilBufferTarget;
7110 This->stencilBufferTarget = pNewZStencil;
7111 /* should we be calling the parent or the wined3d surface? */
7112 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
7113 if (NULL != tmp) IWineD3DSurface_Release(tmp);
7116 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
7117 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
7118 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
7119 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
7120 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
7127 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
7128 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
7129 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7130 /* TODO: the use of Impl is deprecated. */
7131 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
7132 WINED3DLOCKED_RECT lockedRect;
7134 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
7136 /* some basic validation checks */
7137 if(This->cursorTexture) {
7138 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7140 glDeleteTextures(1, &This->cursorTexture);
7142 This->cursorTexture = 0;
7145 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
7146 This->haveHardwareCursor = TRUE;
7148 This->haveHardwareCursor = FALSE;
7151 WINED3DLOCKED_RECT rect;
7153 /* MSDN: Cursor must be A8R8G8B8 */
7154 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format_desc->format)
7156 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
7157 return WINED3DERR_INVALIDCALL;
7160 /* MSDN: Cursor must be smaller than the display mode */
7161 if(pSur->currentDesc.Width > This->ddraw_width ||
7162 pSur->currentDesc.Height > This->ddraw_height) {
7163 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);
7164 return WINED3DERR_INVALIDCALL;
7167 if (!This->haveHardwareCursor) {
7168 /* TODO: MSDN: Cursor sizes must be a power of 2 */
7170 /* Do not store the surface's pointer because the application may
7171 * release it after setting the cursor image. Windows doesn't
7172 * addref the set surface, so we can't do this either without
7173 * creating circular refcount dependencies. Copy out the gl texture
7176 This->cursorWidth = pSur->currentDesc.Width;
7177 This->cursorHeight = pSur->currentDesc.Height;
7178 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
7180 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION);
7181 char *mem, *bits = rect.pBits;
7182 GLint intfmt = glDesc->glInternal;
7183 GLint format = glDesc->glFormat;
7184 GLint type = glDesc->glType;
7185 INT height = This->cursorHeight;
7186 INT width = This->cursorWidth;
7187 INT bpp = glDesc->byte_count;
7190 /* Reformat the texture memory (pitch and width can be
7192 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
7193 for(i = 0; i < height; i++)
7194 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
7195 IWineD3DSurface_UnlockRect(pCursorBitmap);
7198 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
7199 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
7200 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
7203 /* Make sure that a proper texture unit is selected */
7204 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
7205 checkGLcall("glActiveTextureARB");
7206 sampler = This->rev_tex_unit_map[0];
7207 if (sampler != -1) {
7208 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
7210 /* Create a new cursor texture */
7211 glGenTextures(1, &This->cursorTexture);
7212 checkGLcall("glGenTextures");
7213 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
7214 checkGLcall("glBindTexture");
7215 /* Copy the bitmap memory into the cursor texture */
7216 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
7217 HeapFree(GetProcessHeap(), 0, mem);
7218 checkGLcall("glTexImage2D");
7220 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
7221 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
7222 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
7229 FIXME("A cursor texture was not returned.\n");
7230 This->cursorTexture = 0;
7235 /* Draw a hardware cursor */
7236 ICONINFO cursorInfo;
7238 /* Create and clear maskBits because it is not needed for
7239 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
7241 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
7242 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
7243 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
7244 WINED3DLOCK_NO_DIRTY_UPDATE |
7245 WINED3DLOCK_READONLY
7247 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
7248 pSur->currentDesc.Height);
7250 cursorInfo.fIcon = FALSE;
7251 cursorInfo.xHotspot = XHotSpot;
7252 cursorInfo.yHotspot = YHotSpot;
7253 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
7254 pSur->currentDesc.Height, 1,
7256 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
7257 pSur->currentDesc.Height, 1,
7258 32, lockedRect.pBits);
7259 IWineD3DSurface_UnlockRect(pCursorBitmap);
7260 /* Create our cursor and clean up. */
7261 cursor = CreateIconIndirect(&cursorInfo);
7263 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
7264 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
7265 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
7266 This->hardwareCursor = cursor;
7267 HeapFree(GetProcessHeap(), 0, maskBits);
7271 This->xHotSpot = XHotSpot;
7272 This->yHotSpot = YHotSpot;
7276 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7277 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7278 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7280 This->xScreenSpace = XScreenSpace;
7281 This->yScreenSpace = YScreenSpace;
7287 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7289 BOOL oldVisible = This->bCursorVisible;
7292 TRACE("(%p) : visible(%d)\n", This, bShow);
7295 * When ShowCursor is first called it should make the cursor appear at the OS's last
7296 * known cursor position. Because of this, some applications just repetitively call
7297 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
7300 This->xScreenSpace = pt.x;
7301 This->yScreenSpace = pt.y;
7303 if (This->haveHardwareCursor) {
7304 This->bCursorVisible = bShow;
7306 SetCursor(This->hardwareCursor);
7312 if (This->cursorTexture)
7313 This->bCursorVisible = bShow;
7319 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7321 IWineD3DResourceImpl *resource;
7322 TRACE("(%p) : state (%u)\n", This, This->state);
7324 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
7325 switch (This->state) {
7328 case WINED3DERR_DEVICELOST:
7330 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7331 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
7332 return WINED3DERR_DEVICENOTRESET;
7334 return WINED3DERR_DEVICELOST;
7336 case WINED3DERR_DRIVERINTERNALERROR:
7337 return WINED3DERR_DRIVERINTERNALERROR;
7341 return WINED3DERR_DRIVERINTERNALERROR;
7345 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7346 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7347 /** FIXME: Resource tracking needs to be done,
7348 * The closes we can do to this is set the priorities of all managed textures low
7349 * and then reset them.
7350 ***********************************************************/
7351 FIXME("(%p) : stub\n", This);
7355 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
7357 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
7359 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7360 if(surface->Flags & SFLAG_DIBSECTION) {
7361 /* Release the DC */
7362 SelectObject(surface->hDC, surface->dib.holdbitmap);
7363 DeleteDC(surface->hDC);
7364 /* Release the DIB section */
7365 DeleteObject(surface->dib.DIBsection);
7366 surface->dib.bitmap_data = NULL;
7367 surface->resource.allocatedMemory = NULL;
7368 surface->Flags &= ~SFLAG_DIBSECTION;
7370 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7371 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7372 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
7373 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
7374 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7375 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7377 surface->pow2Width = surface->pow2Height = 1;
7378 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7379 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7381 surface->glRect.left = 0;
7382 surface->glRect.top = 0;
7383 surface->glRect.right = surface->pow2Width;
7384 surface->glRect.bottom = surface->pow2Height;
7386 if(surface->glDescription.textureName) {
7387 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7389 glDeleteTextures(1, &surface->glDescription.textureName);
7391 surface->glDescription.textureName = 0;
7392 surface->Flags &= ~SFLAG_CLIENT;
7394 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7395 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7396 surface->Flags |= SFLAG_NONPOW2;
7398 surface->Flags &= ~SFLAG_NONPOW2;
7400 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7401 surface->resource.allocatedMemory = NULL;
7402 surface->resource.heapMemory = NULL;
7403 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7404 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7405 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7406 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7408 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7412 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7413 TRACE("Unloading resource %p\n", resource);
7414 IWineD3DResource_UnLoad(resource);
7415 IWineD3DResource_Release(resource);
7419 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
7422 WINED3DDISPLAYMODE m;
7425 /* All Windowed modes are supported, as is leaving the current mode */
7426 if(pp->Windowed) return TRUE;
7427 if(!pp->BackBufferWidth) return TRUE;
7428 if(!pp->BackBufferHeight) return TRUE;
7430 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7431 for(i = 0; i < count; i++) {
7432 memset(&m, 0, sizeof(m));
7433 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7435 ERR("EnumAdapterModes failed\n");
7437 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7438 /* Mode found, it is supported */
7442 /* Mode not found -> not supported */
7446 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7447 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7448 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7450 IWineD3DBaseShaderImpl *shader;
7452 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7453 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7454 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7458 if(This->depth_blt_texture) {
7459 glDeleteTextures(1, &This->depth_blt_texture);
7460 This->depth_blt_texture = 0;
7462 if (This->depth_blt_rb) {
7463 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7464 This->depth_blt_rb = 0;
7465 This->depth_blt_rb_w = 0;
7466 This->depth_blt_rb_h = 0;
7470 This->blitter->free_private(iface);
7471 This->frag_pipe->free_private(iface);
7472 This->shader_backend->shader_free_private(iface);
7475 for (i = 0; i < GL_LIMITS(textures); i++) {
7476 /* Textures are recreated below */
7477 glDeleteTextures(1, &This->dummyTextureName[i]);
7478 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7479 This->dummyTextureName[i] = 0;
7483 while(This->numContexts) {
7484 DestroyContext(This, This->contexts[0]);
7486 This->activeContext = NULL;
7487 HeapFree(GetProcessHeap(), 0, swapchain->context);
7488 swapchain->context = NULL;
7489 swapchain->num_contexts = 0;
7492 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7493 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7494 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7496 IWineD3DSurfaceImpl *target;
7498 /* Recreate the primary swapchain's context */
7499 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7500 if(swapchain->backBuffer) {
7501 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7503 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7505 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7506 &swapchain->presentParms);
7507 swapchain->num_contexts = 1;
7508 This->activeContext = swapchain->context[0];
7510 create_dummy_textures(This);
7512 hr = This->shader_backend->shader_alloc_private(iface);
7514 ERR("Failed to recreate shader private data\n");
7517 hr = This->frag_pipe->alloc_private(iface);
7519 TRACE("Fragment pipeline private data couldn't be allocated\n");
7522 hr = This->blitter->alloc_private(iface);
7524 TRACE("Blitter private data couldn't be allocated\n");
7531 This->blitter->free_private(iface);
7532 This->frag_pipe->free_private(iface);
7533 This->shader_backend->shader_free_private(iface);
7537 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7538 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7539 IWineD3DSwapChainImpl *swapchain;
7541 BOOL DisplayModeChanged = FALSE;
7542 WINED3DDISPLAYMODE mode;
7543 TRACE("(%p)\n", This);
7545 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7547 ERR("Failed to get the first implicit swapchain\n");
7551 if(!is_display_mode_supported(This, pPresentationParameters)) {
7552 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7553 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7554 pPresentationParameters->BackBufferHeight);
7555 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
7556 return WINED3DERR_INVALIDCALL;
7559 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7560 * on an existing gl context, so there's no real need for recreation.
7562 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7564 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7566 TRACE("New params:\n");
7567 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7568 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7569 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7570 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7571 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7572 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7573 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7574 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7575 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7576 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7577 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7578 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7579 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7581 /* No special treatment of these parameters. Just store them */
7582 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7583 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7584 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7585 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7587 /* What to do about these? */
7588 if(pPresentationParameters->BackBufferCount != 0 &&
7589 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7590 ERR("Cannot change the back buffer count yet\n");
7592 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7593 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7594 ERR("Cannot change the back buffer format yet\n");
7596 if(pPresentationParameters->hDeviceWindow != NULL &&
7597 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7598 ERR("Cannot change the device window yet\n");
7600 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7603 TRACE("Creating the depth stencil buffer\n");
7605 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
7607 pPresentationParameters->BackBufferWidth,
7608 pPresentationParameters->BackBufferHeight,
7609 pPresentationParameters->AutoDepthStencilFormat,
7610 pPresentationParameters->MultiSampleType,
7611 pPresentationParameters->MultiSampleQuality,
7613 &This->auto_depth_stencil_buffer);
7616 ERR("Failed to create the depth stencil buffer\n");
7617 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7618 return WINED3DERR_INVALIDCALL;
7622 /* Reset the depth stencil */
7623 if (pPresentationParameters->EnableAutoDepthStencil)
7624 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7626 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7628 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7630 if(pPresentationParameters->Windowed) {
7631 mode.Width = swapchain->orig_width;
7632 mode.Height = swapchain->orig_height;
7633 mode.RefreshRate = 0;
7634 mode.Format = swapchain->presentParms.BackBufferFormat;
7636 mode.Width = pPresentationParameters->BackBufferWidth;
7637 mode.Height = pPresentationParameters->BackBufferHeight;
7638 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7639 mode.Format = swapchain->presentParms.BackBufferFormat;
7642 /* Should Width == 800 && Height == 0 set 800x600? */
7643 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7644 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7645 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7649 if(!pPresentationParameters->Windowed) {
7650 DisplayModeChanged = TRUE;
7652 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7653 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7655 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7656 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7657 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7659 if(This->auto_depth_stencil_buffer) {
7660 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7664 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7665 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7666 DisplayModeChanged) {
7668 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7670 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7671 if(swapchain->presentParms.Windowed) {
7672 /* switch from windowed to fs */
7673 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7674 pPresentationParameters->BackBufferWidth,
7675 pPresentationParameters->BackBufferHeight);
7677 /* Fullscreen -> fullscreen mode change */
7678 MoveWindow(swapchain->win_handle, 0, 0,
7679 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7682 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7683 /* Fullscreen -> windowed switch */
7684 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7686 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7687 } else if(!pPresentationParameters->Windowed) {
7688 DWORD style = This->style, exStyle = This->exStyle;
7689 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7690 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7691 * Reset to clear up their mess. Guild Wars also loses the device during that.
7695 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7696 pPresentationParameters->BackBufferWidth,
7697 pPresentationParameters->BackBufferHeight);
7698 This->style = style;
7699 This->exStyle = exStyle;
7702 TRACE("Resetting stateblock\n");
7703 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
7704 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
7706 /* Note: No parent needed for initial internal stateblock */
7707 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
7708 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7709 else TRACE("Created stateblock %p\n", This->stateBlock);
7710 This->updateStateBlock = This->stateBlock;
7711 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
7713 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7715 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7718 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7719 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7721 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7727 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7728 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7729 /** FIXME: always true at the moment **/
7730 if(!bEnableDialogs) {
7731 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7737 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7738 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7739 TRACE("(%p) : pParameters %p\n", This, pParameters);
7741 *pParameters = This->createParms;
7745 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7746 IWineD3DSwapChain *swapchain;
7748 TRACE("Relaying to swapchain\n");
7750 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7751 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7752 IWineD3DSwapChain_Release(swapchain);
7757 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7758 IWineD3DSwapChain *swapchain;
7760 TRACE("Relaying to swapchain\n");
7762 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7763 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7764 IWineD3DSwapChain_Release(swapchain);
7770 /** ********************************************************
7771 * Notification functions
7772 ** ********************************************************/
7773 /** This function must be called in the release of a resource when ref == 0,
7774 * the contents of resource must still be correct,
7775 * any handles to other resource held by the caller must be closed
7776 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7777 *****************************************************/
7778 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7779 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7781 TRACE("(%p) : Adding Resource %p\n", This, resource);
7782 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7785 static void IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7786 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7788 TRACE("(%p) : Removing resource %p\n", This, resource);
7790 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7794 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7795 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7796 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7799 TRACE("(%p) : resource %p\n", This, resource);
7801 context_resource_released(iface, resource, type);
7804 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7805 case WINED3DRTYPE_SURFACE: {
7808 /* Cleanup any FBO attachments if d3d is enabled */
7809 if(This->d3d_initialized) {
7810 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7811 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7813 TRACE("Last active render target destroyed\n");
7814 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7815 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7816 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7817 * and the lastActiveRenderTarget member shouldn't matter
7820 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7821 TRACE("Activating primary back buffer\n");
7822 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7823 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7824 /* Single buffering environment */
7825 TRACE("Activating primary front buffer\n");
7826 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7828 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7829 /* Implicit render target destroyed, that means the device is being destroyed
7830 * whatever we set here, it shouldn't matter
7832 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7835 /* May happen during ddraw uninitialization */
7836 TRACE("Render target set, but swapchain does not exist!\n");
7837 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7841 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7842 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7843 This->render_targets[i] = NULL;
7846 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7847 This->stencilBufferTarget = NULL;
7853 case WINED3DRTYPE_TEXTURE:
7854 case WINED3DRTYPE_CUBETEXTURE:
7855 case WINED3DRTYPE_VOLUMETEXTURE:
7856 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7857 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7858 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7859 This->stateBlock->textures[counter] = NULL;
7861 if (This->updateStateBlock != This->stateBlock ){
7862 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7863 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7864 This->updateStateBlock->textures[counter] = NULL;
7869 case WINED3DRTYPE_VOLUME:
7870 /* TODO: nothing really? */
7872 case WINED3DRTYPE_BUFFER:
7875 TRACE("Cleaning up stream pointers\n");
7877 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7878 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7879 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7881 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7882 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7883 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7884 This->updateStateBlock->streamSource[streamNumber] = 0;
7885 /* Set changed flag? */
7888 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) */
7889 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7890 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7891 This->stateBlock->streamSource[streamNumber] = 0;
7896 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7897 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7898 This->updateStateBlock->pIndexData = NULL;
7901 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7902 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7903 This->stateBlock->pIndexData = NULL;
7910 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7915 /* Remove the resource from the resourceStore */
7916 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7918 TRACE("Resource released\n");
7922 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7924 IWineD3DResourceImpl *resource, *cursor;
7926 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7928 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7929 TRACE("enumerating resource %p\n", resource);
7930 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7931 ret = pCallback((IWineD3DResource *) resource, pData);
7932 if(ret == S_FALSE) {
7933 TRACE("Canceling enumeration\n");
7940 /**********************************************************
7941 * IWineD3DDevice VTbl follows
7942 **********************************************************/
7944 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7946 /*** IUnknown methods ***/
7947 IWineD3DDeviceImpl_QueryInterface,
7948 IWineD3DDeviceImpl_AddRef,
7949 IWineD3DDeviceImpl_Release,
7950 /*** IWineD3DDevice methods ***/
7951 IWineD3DDeviceImpl_GetParent,
7952 /*** Creation methods**/
7953 IWineD3DDeviceImpl_CreateBuffer,
7954 IWineD3DDeviceImpl_CreateVertexBuffer,
7955 IWineD3DDeviceImpl_CreateIndexBuffer,
7956 IWineD3DDeviceImpl_CreateStateBlock,
7957 IWineD3DDeviceImpl_CreateSurface,
7958 IWineD3DDeviceImpl_CreateRendertargetView,
7959 IWineD3DDeviceImpl_CreateTexture,
7960 IWineD3DDeviceImpl_CreateVolumeTexture,
7961 IWineD3DDeviceImpl_CreateVolume,
7962 IWineD3DDeviceImpl_CreateCubeTexture,
7963 IWineD3DDeviceImpl_CreateQuery,
7964 IWineD3DDeviceImpl_CreateSwapChain,
7965 IWineD3DDeviceImpl_CreateVertexDeclaration,
7966 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7967 IWineD3DDeviceImpl_CreateVertexShader,
7968 IWineD3DDeviceImpl_CreatePixelShader,
7969 IWineD3DDeviceImpl_CreatePalette,
7970 /*** Odd functions **/
7971 IWineD3DDeviceImpl_Init3D,
7972 IWineD3DDeviceImpl_InitGDI,
7973 IWineD3DDeviceImpl_Uninit3D,
7974 IWineD3DDeviceImpl_UninitGDI,
7975 IWineD3DDeviceImpl_SetMultithreaded,
7976 IWineD3DDeviceImpl_EvictManagedResources,
7977 IWineD3DDeviceImpl_GetAvailableTextureMem,
7978 IWineD3DDeviceImpl_GetBackBuffer,
7979 IWineD3DDeviceImpl_GetCreationParameters,
7980 IWineD3DDeviceImpl_GetDeviceCaps,
7981 IWineD3DDeviceImpl_GetDirect3D,
7982 IWineD3DDeviceImpl_GetDisplayMode,
7983 IWineD3DDeviceImpl_SetDisplayMode,
7984 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7985 IWineD3DDeviceImpl_GetRasterStatus,
7986 IWineD3DDeviceImpl_GetSwapChain,
7987 IWineD3DDeviceImpl_Reset,
7988 IWineD3DDeviceImpl_SetDialogBoxMode,
7989 IWineD3DDeviceImpl_SetCursorProperties,
7990 IWineD3DDeviceImpl_SetCursorPosition,
7991 IWineD3DDeviceImpl_ShowCursor,
7992 IWineD3DDeviceImpl_TestCooperativeLevel,
7993 /*** Getters and setters **/
7994 IWineD3DDeviceImpl_SetClipPlane,
7995 IWineD3DDeviceImpl_GetClipPlane,
7996 IWineD3DDeviceImpl_SetClipStatus,
7997 IWineD3DDeviceImpl_GetClipStatus,
7998 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7999 IWineD3DDeviceImpl_GetCurrentTexturePalette,
8000 IWineD3DDeviceImpl_SetDepthStencilSurface,
8001 IWineD3DDeviceImpl_GetDepthStencilSurface,
8002 IWineD3DDeviceImpl_SetGammaRamp,
8003 IWineD3DDeviceImpl_GetGammaRamp,
8004 IWineD3DDeviceImpl_SetIndices,
8005 IWineD3DDeviceImpl_GetIndices,
8006 IWineD3DDeviceImpl_SetBaseVertexIndex,
8007 IWineD3DDeviceImpl_GetBaseVertexIndex,
8008 IWineD3DDeviceImpl_SetLight,
8009 IWineD3DDeviceImpl_GetLight,
8010 IWineD3DDeviceImpl_SetLightEnable,
8011 IWineD3DDeviceImpl_GetLightEnable,
8012 IWineD3DDeviceImpl_SetMaterial,
8013 IWineD3DDeviceImpl_GetMaterial,
8014 IWineD3DDeviceImpl_SetNPatchMode,
8015 IWineD3DDeviceImpl_GetNPatchMode,
8016 IWineD3DDeviceImpl_SetPaletteEntries,
8017 IWineD3DDeviceImpl_GetPaletteEntries,
8018 IWineD3DDeviceImpl_SetPixelShader,
8019 IWineD3DDeviceImpl_GetPixelShader,
8020 IWineD3DDeviceImpl_SetPixelShaderConstantB,
8021 IWineD3DDeviceImpl_GetPixelShaderConstantB,
8022 IWineD3DDeviceImpl_SetPixelShaderConstantI,
8023 IWineD3DDeviceImpl_GetPixelShaderConstantI,
8024 IWineD3DDeviceImpl_SetPixelShaderConstantF,
8025 IWineD3DDeviceImpl_GetPixelShaderConstantF,
8026 IWineD3DDeviceImpl_SetRenderState,
8027 IWineD3DDeviceImpl_GetRenderState,
8028 IWineD3DDeviceImpl_SetRenderTarget,
8029 IWineD3DDeviceImpl_GetRenderTarget,
8030 IWineD3DDeviceImpl_SetFrontBackBuffers,
8031 IWineD3DDeviceImpl_SetSamplerState,
8032 IWineD3DDeviceImpl_GetSamplerState,
8033 IWineD3DDeviceImpl_SetScissorRect,
8034 IWineD3DDeviceImpl_GetScissorRect,
8035 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
8036 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
8037 IWineD3DDeviceImpl_SetStreamSource,
8038 IWineD3DDeviceImpl_GetStreamSource,
8039 IWineD3DDeviceImpl_SetStreamSourceFreq,
8040 IWineD3DDeviceImpl_GetStreamSourceFreq,
8041 IWineD3DDeviceImpl_SetTexture,
8042 IWineD3DDeviceImpl_GetTexture,
8043 IWineD3DDeviceImpl_SetTextureStageState,
8044 IWineD3DDeviceImpl_GetTextureStageState,
8045 IWineD3DDeviceImpl_SetTransform,
8046 IWineD3DDeviceImpl_GetTransform,
8047 IWineD3DDeviceImpl_SetVertexDeclaration,
8048 IWineD3DDeviceImpl_GetVertexDeclaration,
8049 IWineD3DDeviceImpl_SetVertexShader,
8050 IWineD3DDeviceImpl_GetVertexShader,
8051 IWineD3DDeviceImpl_SetVertexShaderConstantB,
8052 IWineD3DDeviceImpl_GetVertexShaderConstantB,
8053 IWineD3DDeviceImpl_SetVertexShaderConstantI,
8054 IWineD3DDeviceImpl_GetVertexShaderConstantI,
8055 IWineD3DDeviceImpl_SetVertexShaderConstantF,
8056 IWineD3DDeviceImpl_GetVertexShaderConstantF,
8057 IWineD3DDeviceImpl_SetViewport,
8058 IWineD3DDeviceImpl_GetViewport,
8059 IWineD3DDeviceImpl_MultiplyTransform,
8060 IWineD3DDeviceImpl_ValidateDevice,
8061 IWineD3DDeviceImpl_ProcessVertices,
8062 /*** State block ***/
8063 IWineD3DDeviceImpl_BeginStateBlock,
8064 IWineD3DDeviceImpl_EndStateBlock,
8065 /*** Scene management ***/
8066 IWineD3DDeviceImpl_BeginScene,
8067 IWineD3DDeviceImpl_EndScene,
8068 IWineD3DDeviceImpl_Present,
8069 IWineD3DDeviceImpl_Clear,
8070 IWineD3DDeviceImpl_ClearRendertargetView,
8072 IWineD3DDeviceImpl_SetPrimitiveType,
8073 IWineD3DDeviceImpl_GetPrimitiveType,
8074 IWineD3DDeviceImpl_DrawPrimitive,
8075 IWineD3DDeviceImpl_DrawIndexedPrimitive,
8076 IWineD3DDeviceImpl_DrawPrimitiveUP,
8077 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
8078 IWineD3DDeviceImpl_DrawPrimitiveStrided,
8079 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
8080 IWineD3DDeviceImpl_DrawRectPatch,
8081 IWineD3DDeviceImpl_DrawTriPatch,
8082 IWineD3DDeviceImpl_DeletePatch,
8083 IWineD3DDeviceImpl_ColorFill,
8084 IWineD3DDeviceImpl_UpdateTexture,
8085 IWineD3DDeviceImpl_UpdateSurface,
8086 IWineD3DDeviceImpl_GetFrontBufferData,
8087 /*** object tracking ***/
8088 IWineD3DDeviceImpl_ResourceReleased,
8089 IWineD3DDeviceImpl_EnumResources
8092 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
8093 WINED3DRS_ALPHABLENDENABLE ,
8094 WINED3DRS_ALPHAFUNC ,
8095 WINED3DRS_ALPHAREF ,
8096 WINED3DRS_ALPHATESTENABLE ,
8098 WINED3DRS_COLORWRITEENABLE ,
8099 WINED3DRS_DESTBLEND ,
8100 WINED3DRS_DITHERENABLE ,
8101 WINED3DRS_FILLMODE ,
8102 WINED3DRS_FOGDENSITY ,
8104 WINED3DRS_FOGSTART ,
8105 WINED3DRS_LASTPIXEL ,
8106 WINED3DRS_SHADEMODE ,
8107 WINED3DRS_SRCBLEND ,
8108 WINED3DRS_STENCILENABLE ,
8109 WINED3DRS_STENCILFAIL ,
8110 WINED3DRS_STENCILFUNC ,
8111 WINED3DRS_STENCILMASK ,
8112 WINED3DRS_STENCILPASS ,
8113 WINED3DRS_STENCILREF ,
8114 WINED3DRS_STENCILWRITEMASK ,
8115 WINED3DRS_STENCILZFAIL ,
8116 WINED3DRS_TEXTUREFACTOR ,
8127 WINED3DRS_ZWRITEENABLE
8130 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
8131 WINED3DTSS_ALPHAARG0 ,
8132 WINED3DTSS_ALPHAARG1 ,
8133 WINED3DTSS_ALPHAARG2 ,
8134 WINED3DTSS_ALPHAOP ,
8135 WINED3DTSS_BUMPENVLOFFSET ,
8136 WINED3DTSS_BUMPENVLSCALE ,
8137 WINED3DTSS_BUMPENVMAT00 ,
8138 WINED3DTSS_BUMPENVMAT01 ,
8139 WINED3DTSS_BUMPENVMAT10 ,
8140 WINED3DTSS_BUMPENVMAT11 ,
8141 WINED3DTSS_COLORARG0 ,
8142 WINED3DTSS_COLORARG1 ,
8143 WINED3DTSS_COLORARG2 ,
8144 WINED3DTSS_COLOROP ,
8145 WINED3DTSS_RESULTARG ,
8146 WINED3DTSS_TEXCOORDINDEX ,
8147 WINED3DTSS_TEXTURETRANSFORMFLAGS
8150 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
8151 WINED3DSAMP_ADDRESSU ,
8152 WINED3DSAMP_ADDRESSV ,
8153 WINED3DSAMP_ADDRESSW ,
8154 WINED3DSAMP_BORDERCOLOR ,
8155 WINED3DSAMP_MAGFILTER ,
8156 WINED3DSAMP_MINFILTER ,
8157 WINED3DSAMP_MIPFILTER ,
8158 WINED3DSAMP_MIPMAPLODBIAS ,
8159 WINED3DSAMP_MAXMIPLEVEL ,
8160 WINED3DSAMP_MAXANISOTROPY ,
8161 WINED3DSAMP_SRGBTEXTURE ,
8162 WINED3DSAMP_ELEMENTINDEX
8165 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
8167 WINED3DRS_AMBIENTMATERIALSOURCE ,
8168 WINED3DRS_CLIPPING ,
8169 WINED3DRS_CLIPPLANEENABLE ,
8170 WINED3DRS_COLORVERTEX ,
8171 WINED3DRS_DIFFUSEMATERIALSOURCE ,
8172 WINED3DRS_EMISSIVEMATERIALSOURCE ,
8173 WINED3DRS_FOGDENSITY ,
8175 WINED3DRS_FOGSTART ,
8176 WINED3DRS_FOGTABLEMODE ,
8177 WINED3DRS_FOGVERTEXMODE ,
8178 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
8179 WINED3DRS_LIGHTING ,
8180 WINED3DRS_LOCALVIEWER ,
8181 WINED3DRS_MULTISAMPLEANTIALIAS ,
8182 WINED3DRS_MULTISAMPLEMASK ,
8183 WINED3DRS_NORMALIZENORMALS ,
8184 WINED3DRS_PATCHEDGESTYLE ,
8185 WINED3DRS_POINTSCALE_A ,
8186 WINED3DRS_POINTSCALE_B ,
8187 WINED3DRS_POINTSCALE_C ,
8188 WINED3DRS_POINTSCALEENABLE ,
8189 WINED3DRS_POINTSIZE ,
8190 WINED3DRS_POINTSIZE_MAX ,
8191 WINED3DRS_POINTSIZE_MIN ,
8192 WINED3DRS_POINTSPRITEENABLE ,
8193 WINED3DRS_RANGEFOGENABLE ,
8194 WINED3DRS_SPECULARMATERIALSOURCE ,
8195 WINED3DRS_TWEENFACTOR ,
8196 WINED3DRS_VERTEXBLEND ,
8197 WINED3DRS_CULLMODE ,
8201 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8202 WINED3DTSS_TEXCOORDINDEX ,
8203 WINED3DTSS_TEXTURETRANSFORMFLAGS
8206 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8207 WINED3DSAMP_DMAPOFFSET
8210 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
8211 DWORD rep = This->StateTable[state].representative;
8215 WineD3DContext *context;
8218 for(i = 0; i < This->numContexts; i++) {
8219 context = This->contexts[i];
8220 if(isStateDirty(context, rep)) continue;
8222 context->dirtyArray[context->numDirtyEntries++] = rep;
8225 context->isStateDirty[idx] |= (1 << shift);
8229 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8230 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8231 /* The drawable size of a pbuffer render target is the current pbuffer size
8233 *width = dev->pbufferWidth;
8234 *height = dev->pbufferHeight;
8237 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8238 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
8240 *width = This->pow2Width;
8241 *height = This->pow2Height;
8244 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8245 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8246 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
8247 * current context's drawable, which is the size of the back buffer of the swapchain
8248 * the active context belongs to. The back buffer of the swapchain is stored as the
8249 * surface the context belongs to.
8251 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
8252 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;