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 /**********************************************************
55 * Global variable / Constants follow
56 **********************************************************/
57 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
59 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
60 * actually have the same values in GL and D3D. */
61 static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
63 switch(primitive_type)
65 case WINED3DPT_POINTLIST:
68 case WINED3DPT_LINELIST:
71 case WINED3DPT_LINESTRIP:
74 case WINED3DPT_TRIANGLELIST:
77 case WINED3DPT_TRIANGLESTRIP:
78 return GL_TRIANGLE_STRIP;
80 case WINED3DPT_TRIANGLEFAN:
81 return GL_TRIANGLE_FAN;
83 case WINED3DPT_LINELIST_ADJ:
84 return GL_LINES_ADJACENCY_ARB;
86 case WINED3DPT_LINESTRIP_ADJ:
87 return GL_LINE_STRIP_ADJACENCY_ARB;
89 case WINED3DPT_TRIANGLELIST_ADJ:
90 return GL_TRIANGLES_ADJACENCY_ARB;
92 case WINED3DPT_TRIANGLESTRIP_ADJ:
93 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
96 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
101 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
103 switch(primitive_type)
106 return WINED3DPT_POINTLIST;
109 return WINED3DPT_LINELIST;
112 return WINED3DPT_LINESTRIP;
115 return WINED3DPT_TRIANGLELIST;
117 case GL_TRIANGLE_STRIP:
118 return WINED3DPT_TRIANGLESTRIP;
120 case GL_TRIANGLE_FAN:
121 return WINED3DPT_TRIANGLEFAN;
123 case GL_LINES_ADJACENCY_ARB:
124 return WINED3DPT_LINELIST_ADJ;
126 case GL_LINE_STRIP_ADJACENCY_ARB:
127 return WINED3DPT_LINESTRIP_ADJ;
129 case GL_TRIANGLES_ADJACENCY_ARB:
130 return WINED3DPT_TRIANGLELIST_ADJ;
132 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
133 return WINED3DPT_TRIANGLESTRIP_ADJ;
136 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
137 return WINED3DPT_UNDEFINED;
141 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
143 if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && usage_idx == 0)
144 *regnum = WINED3D_FFP_POSITION;
145 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
146 *regnum = WINED3D_FFP_BLENDWEIGHT;
147 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
148 *regnum = WINED3D_FFP_BLENDINDICES;
149 else if (usage == WINED3DDECLUSAGE_NORMAL && usage_idx == 0)
150 *regnum = WINED3D_FFP_NORMAL;
151 else if (usage == WINED3DDECLUSAGE_PSIZE && usage_idx == 0)
152 *regnum = WINED3D_FFP_PSIZE;
153 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 0)
154 *regnum = WINED3D_FFP_DIFFUSE;
155 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1)
156 *regnum = WINED3D_FFP_SPECULAR;
157 else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
158 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
161 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
169 void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
170 BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
172 /* We need to deal with frequency data! */
173 IWineD3DVertexDeclarationImpl *declaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
174 UINT stream_count = This->stateBlock->streamIsUP ? 0 : declaration->num_streams;
175 const DWORD *streams = declaration->streams;
178 memset(stream_info, 0, sizeof(*stream_info));
180 /* Check for transformed vertices, disable vertex shader if present. */
181 stream_info->position_transformed = declaration->position_transformed;
182 if (declaration->position_transformed) use_vshader = FALSE;
184 /* Translate the declaration into strided data. */
185 for (i = 0; i < declaration->element_count; ++i)
187 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
188 GLuint buffer_object = 0;
189 const BYTE *data = NULL;
194 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
195 element, i + 1, declaration->element_count);
197 if (!This->stateBlock->streamSource[element->input_slot]) continue;
199 stride = This->stateBlock->streamStride[element->input_slot];
200 if (This->stateBlock->streamIsUP)
202 TRACE("Stream %u is UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
204 data = (BYTE *)This->stateBlock->streamSource[element->input_slot];
208 TRACE("Stream %u isn't UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
209 data = buffer_get_memory(This->stateBlock->streamSource[element->input_slot], 0, &buffer_object);
211 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
212 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
213 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
214 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
215 * not, drawStridedSlow is needed, including a vertex buffer path. */
216 if (This->stateBlock->loadBaseVertexIndex < 0)
218 WARN("loadBaseVertexIndex is < 0 (%d), not using vbos\n", This->stateBlock->loadBaseVertexIndex);
220 data = buffer_get_sysmem((struct wined3d_buffer *)This->stateBlock->streamSource[element->input_slot]);
221 if ((UINT_PTR)data < -This->stateBlock->loadBaseVertexIndex * stride)
223 FIXME("System memory vertex data load offset is negative!\n");
229 if (buffer_object) *fixup = TRUE;
230 else if (*fixup && !use_vshader
231 && (element->usage == WINED3DDECLUSAGE_COLOR
232 || element->usage == WINED3DDECLUSAGE_POSITIONT))
234 static BOOL warned = FALSE;
237 /* This may be bad with the fixed function pipeline. */
238 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
244 data += element->offset;
246 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
250 if (element->output_slot == ~0U)
252 /* TODO: Assuming vertexdeclarations are usually used with the
253 * same or a similar shader, it might be worth it to store the
254 * last used output slot and try that one first. */
255 stride_used = vshader_get_input(This->stateBlock->vertexShader,
256 element->usage, element->usage_idx, &idx);
260 idx = element->output_slot;
266 if (!element->ffp_valid)
268 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
269 debug_d3dformat(element->format_desc->format), debug_d3ddeclusage(element->usage));
274 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
280 TRACE("Load %s array %u [usage %s, usage_idx %u, "
281 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
282 use_vshader ? "shader": "fixed function", idx,
283 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
284 element->offset, stride, debug_d3dformat(element->format_desc->format), buffer_object);
286 stream_info->elements[idx].format_desc = element->format_desc;
287 stream_info->elements[idx].stride = stride;
288 stream_info->elements[idx].data = data;
289 stream_info->elements[idx].stream_idx = element->input_slot;
290 stream_info->elements[idx].buffer_object = buffer_object;
292 if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA) && element->format_desc->format == WINED3DFMT_A8R8G8B8)
294 stream_info->swizzle_map |= 1 << idx;
296 stream_info->use_map |= 1 << idx;
300 /* Now call PreLoad on all the vertex buffers. In the very rare case
301 * that the buffers stopps converting PreLoad will dirtify the VDECL again.
302 * The vertex buffer can now use the strided structure in the device instead of finding its
305 * NULL streams won't be recorded in the array, UP streams won't be either. A stream is only
307 for (i = 0; i < stream_count; ++i)
309 IWineD3DBuffer *vb = This->stateBlock->streamSource[streams[i]];
310 if (vb) IWineD3DBuffer_PreLoad(vb);
314 static void stream_info_element_from_strided(IWineD3DDeviceImpl *This,
315 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
317 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(strided->format, &This->adapter->gl_info);
318 e->format_desc = format_desc;
319 e->stride = strided->dwStride;
320 e->data = strided->lpData;
322 e->buffer_object = 0;
325 void device_stream_info_from_strided(IWineD3DDeviceImpl *This,
326 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
330 memset(stream_info, 0, sizeof(*stream_info));
332 if (strided->position.lpData)
333 stream_info_element_from_strided(This, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
334 if (strided->normal.lpData)
335 stream_info_element_from_strided(This, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
336 if (strided->diffuse.lpData)
337 stream_info_element_from_strided(This, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
338 if (strided->specular.lpData)
339 stream_info_element_from_strided(This, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
341 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
343 if (strided->texCoords[i].lpData)
344 stream_info_element_from_strided(This, &strided->texCoords[i],
345 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
348 stream_info->position_transformed = strided->position_transformed;
350 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
352 if (!stream_info->elements[i].format_desc) continue;
354 if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA) && stream_info->elements[i].format_desc->format == WINED3DFMT_A8R8G8B8)
356 stream_info->swizzle_map |= 1 << i;
358 stream_info->use_map |= 1 << i;
362 /**********************************************************
363 * IUnknown parts follows
364 **********************************************************/
366 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
368 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
370 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
371 if (IsEqualGUID(riid, &IID_IUnknown)
372 || IsEqualGUID(riid, &IID_IWineD3DBase)
373 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
374 IUnknown_AddRef(iface);
379 return E_NOINTERFACE;
382 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
383 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
384 ULONG refCount = InterlockedIncrement(&This->ref);
386 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
390 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
391 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
392 ULONG refCount = InterlockedDecrement(&This->ref);
394 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
399 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
400 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
401 This->multistate_funcs[i] = NULL;
404 /* TODO: Clean up all the surfaces and textures! */
405 /* NOTE: You must release the parent if the object was created via a callback
406 ** ***************************/
408 if (!list_empty(&This->resources)) {
409 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
410 dumpResources(&This->resources);
413 if(This->contexts) ERR("Context array not freed!\n");
414 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
415 This->haveHardwareCursor = FALSE;
417 IWineD3D_Release(This->wineD3D);
418 This->wineD3D = NULL;
419 HeapFree(GetProcessHeap(), 0, This);
420 TRACE("Freed device %p\n", This);
426 /**********************************************************
427 * IWineD3DDevice implementation follows
428 **********************************************************/
429 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
430 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
431 *pParent = This->parent;
432 IUnknown_AddRef(This->parent);
436 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface,
437 struct wined3d_buffer_desc *desc, const void *data, IUnknown *parent, IWineD3DBuffer **buffer)
439 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
440 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(WINED3DFMT_UNKNOWN, &This->adapter->gl_info);
441 struct wined3d_buffer *object;
444 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
446 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
449 ERR("Failed to allocate memory\n");
450 return E_OUTOFMEMORY;
453 object->vtbl = &wined3d_buffer_vtbl;
454 object->desc = *desc;
456 FIXME("Ignoring access flags (pool)\n");
458 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_BUFFER, This, desc->byte_width,
459 desc->usage, format_desc, WINED3DPOOL_MANAGED, parent);
462 WARN("Failed to initialize resource, returning %#x\n", hr);
463 HeapFree(GetProcessHeap(), 0, object);
466 object->buffer_type_hint = GL_ARRAY_BUFFER_ARB;
468 TRACE("Created resource %p\n", object);
470 TRACE("size %#x, usage=%#x, format %s, memory @ %p, iface @ %p\n", object->resource.size, object->resource.usage,
471 debug_d3dformat(object->resource.format_desc->format), object->resource.allocatedMemory, object);
477 hr = IWineD3DBuffer_Map((IWineD3DBuffer *)object, 0, desc->byte_width, &ptr, 0);
480 ERR("Failed to map buffer, hr %#x\n", hr);
481 IWineD3DBuffer_Release((IWineD3DBuffer *)object);
485 memcpy(ptr, data, desc->byte_width);
487 hr = IWineD3DBuffer_Unmap((IWineD3DBuffer *)object);
490 ERR("Failed to unmap buffer, hr %#x\n", hr);
491 IWineD3DBuffer_Release((IWineD3DBuffer *)object);
496 *buffer = (IWineD3DBuffer *)object;
501 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
502 DWORD FVF, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer, IUnknown *parent)
504 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
505 /* Dummy format for now */
506 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(WINED3DFMT_VERTEXDATA, &This->adapter->gl_info);
507 struct wined3d_buffer *object;
508 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
513 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
514 *ppVertexBuffer = NULL;
515 return WINED3DERR_INVALIDCALL;
516 } else if(Pool == WINED3DPOOL_SCRATCH) {
517 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
518 * anyway, SCRATCH vertex buffers aren't usable anywhere
520 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
521 *ppVertexBuffer = NULL;
522 return WINED3DERR_INVALIDCALL;
525 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
528 ERR("Out of memory\n");
529 *ppVertexBuffer = NULL;
530 return WINED3DERR_OUTOFVIDEOMEMORY;
533 object->vtbl = &wined3d_buffer_vtbl;
534 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_BUFFER, This, Size, Usage, format_desc, Pool, parent);
537 WARN("Failed to initialize resource, returning %#x\n", hr);
538 HeapFree(GetProcessHeap(), 0, object);
539 *ppVertexBuffer = NULL;
542 object->buffer_type_hint = GL_ARRAY_BUFFER_ARB;
544 TRACE("(%p) : Created resource %p\n", This, object);
546 TRACE("(%p) : Size=%d, Usage=0x%08x, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
547 *ppVertexBuffer = (IWineD3DBuffer *)object;
549 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
550 * drawStridedFast (half-life 2).
552 * Basically converting the vertices in the buffer is quite expensive, and observations
553 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
554 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
556 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
557 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
558 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
559 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
561 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
562 * more. In this call we can convert dx7 buffers too.
564 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
565 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
566 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
567 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
568 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
569 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
570 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
571 } else if(dxVersion <= 7 && conv) {
572 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
574 object->flags |= WINED3D_BUFFER_CREATEBO;
579 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
580 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer, IUnknown *parent)
582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
583 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(WINED3DFMT_UNKNOWN, &This->adapter->gl_info);
584 struct wined3d_buffer *object;
587 TRACE("(%p) Creating index buffer\n", This);
589 /* Allocate the storage for the device */
590 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
593 ERR("Out of memory\n");
594 *ppIndexBuffer = NULL;
595 return WINED3DERR_OUTOFVIDEOMEMORY;
598 object->vtbl = &wined3d_buffer_vtbl;
599 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_BUFFER, This, Length, Usage, format_desc, Pool, parent);
602 WARN("Failed to initialize resource, returning %#x\n", hr);
603 HeapFree(GetProcessHeap(), 0, object);
604 *ppIndexBuffer = NULL;
607 object->buffer_type_hint = GL_ELEMENT_ARRAY_BUFFER_ARB;
609 TRACE("(%p) : Created resource %p\n", This, object);
611 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
612 object->flags |= WINED3D_BUFFER_CREATEBO;
615 TRACE("(%p) : Len=%d, Use=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage,
616 Pool, object, object->resource.allocatedMemory);
617 *ppIndexBuffer = (IWineD3DBuffer *) object;
622 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
625 IWineD3DStateBlockImpl *object;
629 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
632 ERR("Out of memory\n");
633 *ppStateBlock = NULL;
634 return WINED3DERR_OUTOFVIDEOMEMORY;
637 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
638 object->wineD3DDevice = This;
639 object->parent = parent;
641 object->blockType = Type;
643 *ppStateBlock = (IWineD3DStateBlock *)object;
645 for(i = 0; i < LIGHTMAP_SIZE; i++) {
646 list_init(&object->lightMap[i]);
649 temp_result = allocate_shader_constants(object);
650 if (FAILED(temp_result))
652 HeapFree(GetProcessHeap(), 0, object);
656 /* Special case - Used during initialization to produce a placeholder stateblock
657 so other functions called can update a state block */
658 if (Type == WINED3DSBT_INIT || Type == WINED3DSBT_RECORDED)
660 /* Don't bother increasing the reference count otherwise a device will never
661 be freed due to circular dependencies */
665 /* Otherwise, might as well set the whole state block to the appropriate values */
666 if (This->stateBlock != NULL)
667 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
669 memset(object->streamFreq, 1, sizeof(object->streamFreq));
671 /* Reset the ref and type after kludging it */
672 object->wineD3DDevice = This;
674 object->blockType = Type;
676 TRACE("Updating changed flags appropriate for type %d\n", Type);
678 if (Type == WINED3DSBT_ALL) {
680 TRACE("ALL => Pretend everything has changed\n");
681 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
683 /* Lights are not part of the changed / set structure */
684 for(j = 0; j < LIGHTMAP_SIZE; j++) {
686 LIST_FOR_EACH(e, &object->lightMap[j]) {
687 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
688 light->changed = TRUE;
689 light->enabledChanged = TRUE;
692 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
693 object->contained_render_states[j - 1] = j;
695 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
696 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
697 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
698 object->contained_transform_states[j - 1] = j;
700 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
701 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
702 object->contained_vs_consts_f[j] = j;
704 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
705 for(j = 0; j < MAX_CONST_I; j++) {
706 object->contained_vs_consts_i[j] = j;
708 object->num_contained_vs_consts_i = MAX_CONST_I;
709 for(j = 0; j < MAX_CONST_B; j++) {
710 object->contained_vs_consts_b[j] = j;
712 object->num_contained_vs_consts_b = MAX_CONST_B;
713 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
714 object->contained_ps_consts_f[j] = j;
716 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
717 for(j = 0; j < MAX_CONST_I; j++) {
718 object->contained_ps_consts_i[j] = j;
720 object->num_contained_ps_consts_i = MAX_CONST_I;
721 for(j = 0; j < MAX_CONST_B; j++) {
722 object->contained_ps_consts_b[j] = j;
724 object->num_contained_ps_consts_b = MAX_CONST_B;
725 for(i = 0; i < MAX_TEXTURES; i++) {
726 for (j = 0; j <= WINED3D_HIGHEST_TEXTURE_STATE; ++j)
728 object->contained_tss_states[object->num_contained_tss_states].stage = i;
729 object->contained_tss_states[object->num_contained_tss_states].state = j;
730 object->num_contained_tss_states++;
733 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
734 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
735 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
736 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
737 object->num_contained_sampler_states++;
741 for(i = 0; i < MAX_STREAMS; i++) {
742 if(object->streamSource[i]) {
743 IWineD3DBuffer_AddRef(object->streamSource[i]);
746 if(object->pIndexData) {
747 IWineD3DBuffer_AddRef(object->pIndexData);
749 if(object->vertexShader) {
750 IWineD3DVertexShader_AddRef(object->vertexShader);
752 if(object->pixelShader) {
753 IWineD3DPixelShader_AddRef(object->pixelShader);
756 } else if (Type == WINED3DSBT_PIXELSTATE) {
758 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
759 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
761 object->changed.pixelShader = TRUE;
763 /* Pixel Shader Constants */
764 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
765 object->contained_ps_consts_f[i] = i;
766 object->changed.pixelShaderConstantsF[i] = TRUE;
768 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
769 for (i = 0; i < MAX_CONST_B; ++i) {
770 object->contained_ps_consts_b[i] = i;
771 object->changed.pixelShaderConstantsB |= (1 << i);
773 object->num_contained_ps_consts_b = MAX_CONST_B;
774 for (i = 0; i < MAX_CONST_I; ++i) {
775 object->contained_ps_consts_i[i] = i;
776 object->changed.pixelShaderConstantsI |= (1 << i);
778 object->num_contained_ps_consts_i = MAX_CONST_I;
780 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
781 DWORD rs = SavedPixelStates_R[i];
782 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
783 object->contained_render_states[i] = rs;
785 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
786 for (j = 0; j < MAX_TEXTURES; j++) {
787 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
788 DWORD state = SavedPixelStates_T[i];
789 object->changed.textureState[j] |= 1 << state;
790 object->contained_tss_states[object->num_contained_tss_states].stage = j;
791 object->contained_tss_states[object->num_contained_tss_states].state = state;
792 object->num_contained_tss_states++;
795 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
796 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
797 DWORD state = SavedPixelStates_S[i];
798 object->changed.samplerState[j] |= 1 << state;
799 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
800 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
801 object->num_contained_sampler_states++;
804 if(object->pixelShader) {
805 IWineD3DPixelShader_AddRef(object->pixelShader);
808 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
809 * on them. This makes releasing the buffer easier
811 for(i = 0; i < MAX_STREAMS; i++) {
812 object->streamSource[i] = NULL;
814 object->pIndexData = NULL;
815 object->vertexShader = NULL;
817 } else if (Type == WINED3DSBT_VERTEXSTATE) {
819 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
820 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
822 object->changed.vertexShader = TRUE;
824 /* Vertex Shader Constants */
825 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
826 object->changed.vertexShaderConstantsF[i] = TRUE;
827 object->contained_vs_consts_f[i] = i;
829 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
830 for (i = 0; i < MAX_CONST_B; ++i) {
831 object->contained_vs_consts_b[i] = i;
832 object->changed.vertexShaderConstantsB |= (1 << i);
834 object->num_contained_vs_consts_b = MAX_CONST_B;
835 for (i = 0; i < MAX_CONST_I; ++i) {
836 object->contained_vs_consts_i[i] = i;
837 object->changed.vertexShaderConstantsI |= (1 << i);
839 object->num_contained_vs_consts_i = MAX_CONST_I;
840 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
841 DWORD rs = SavedVertexStates_R[i];
842 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
843 object->contained_render_states[i] = rs;
845 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
846 for (j = 0; j < MAX_TEXTURES; j++) {
847 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
848 DWORD state = SavedVertexStates_T[i];
849 object->changed.textureState[j] |= 1 << state;
850 object->contained_tss_states[object->num_contained_tss_states].stage = j;
851 object->contained_tss_states[object->num_contained_tss_states].state = state;
852 object->num_contained_tss_states++;
855 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
856 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
857 DWORD state = SavedVertexStates_S[i];
858 object->changed.samplerState[j] |= 1 << state;
859 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
860 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
861 object->num_contained_sampler_states++;
865 for(j = 0; j < LIGHTMAP_SIZE; j++) {
867 LIST_FOR_EACH(e, &object->lightMap[j]) {
868 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
869 light->changed = TRUE;
870 light->enabledChanged = TRUE;
874 for(i = 0; i < MAX_STREAMS; i++) {
875 if(object->streamSource[i]) {
876 IWineD3DBuffer_AddRef(object->streamSource[i]);
879 if(object->vertexShader) {
880 IWineD3DVertexShader_AddRef(object->vertexShader);
882 object->pIndexData = NULL;
883 object->pixelShader = NULL;
885 FIXME("Unrecognized state block type %d\n", Type);
888 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
892 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface,
893 UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level,
894 IWineD3DSurface **ppSurface, WINED3DRESOURCETYPE Type, DWORD Usage, WINED3DPOOL Pool,
895 WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, WINED3DSURFTYPE Impl, IUnknown *parent)
897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
898 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
899 unsigned int Size = 1;
900 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(Format, &GLINFO_LOCATION);
904 TRACE("(%p) Create surface\n",This);
906 if(MultisampleQuality > 0) {
907 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
908 MultisampleQuality=0;
911 /** FIXME: Check that the format is supported
913 *******************************/
915 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
916 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
918 *********************************/
919 mul_4w = (Width + 3) & ~3;
920 mul_4h = (Height + 3) & ~3;
921 if (WINED3DFMT_UNKNOWN == Format) {
923 } else if (Format == WINED3DFMT_DXT1) {
924 /* DXT1 is half byte per pixel */
925 Size = (mul_4w * glDesc->byte_count * mul_4h) >> 1;
927 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
928 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
929 Format == WINED3DFMT_ATI2N) {
930 Size = (mul_4w * glDesc->byte_count * mul_4h);
932 /* The pitch is a multiple of 4 bytes */
933 Size = ((Width * glDesc->byte_count) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
937 if(glDesc->heightscale != 0.0) Size *= glDesc->heightscale;
939 /** Create and initialise the surface resource **/
940 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
943 ERR("Out of memory\n");
945 return WINED3DERR_OUTOFVIDEOMEMORY;
948 /* Look at the implementation and set the correct Vtable */
952 /* Check if a 3D adapter is available when creating gl surfaces */
955 ERR("OpenGL surfaces are not available without opengl\n");
956 HeapFree(GetProcessHeap(), 0, object);
957 return WINED3DERR_NOTAVAILABLE;
959 object->lpVtbl = &IWineD3DSurface_Vtbl;
963 object->lpVtbl = &IWineGDISurface_Vtbl;
967 /* To be sure to catch this */
968 ERR("Unknown requested surface implementation %d!\n", Impl);
969 HeapFree(GetProcessHeap(), 0, object);
970 return WINED3DERR_INVALIDCALL;
973 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_SURFACE, This, Size, Usage, glDesc, Pool, parent);
976 WARN("Failed to initialize resource, returning %#x\n", hr);
977 HeapFree(GetProcessHeap(), 0, object);
982 TRACE("(%p) : Created resource %p\n", This, object);
984 *ppSurface = (IWineD3DSurface *)object;
986 /* "Standalone" surface */
987 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
989 object->currentDesc.Width = Width;
990 object->currentDesc.Height = Height;
991 object->currentDesc.MultiSampleType = MultiSample;
992 object->currentDesc.MultiSampleQuality = MultisampleQuality;
993 object->glDescription.level = Level;
994 list_init(&object->overlays);
997 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
998 object->Flags |= Discard ? SFLAG_DISCARD : 0;
999 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
1000 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
1002 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
1004 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
1005 * this function is too deep to need to care about things like this.
1006 * Levels need to be checked too, and possibly Type since they all affect what can be done.
1007 * ****************************************/
1009 case WINED3DPOOL_SCRATCH:
1011 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
1012 "which are mutually exclusive, setting lockable to TRUE\n");
1015 case WINED3DPOOL_SYSTEMMEM:
1016 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
1017 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
1018 case WINED3DPOOL_MANAGED:
1019 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
1020 "Usage of DYNAMIC which are mutually exclusive, not doing "
1021 "anything just telling you.\n");
1023 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
1024 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
1025 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
1026 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
1029 FIXME("(%p) Unknown pool %d\n", This, Pool);
1033 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
1034 FIXME("Trying to create a render target that isn't in the default pool\n");
1037 /* mark the texture as dirty so that it gets loaded first time around*/
1038 surface_add_dirty_rect(*ppSurface, NULL);
1039 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
1040 This, Width, Height, Format, debug_d3dformat(Format),
1041 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
1043 list_init(&object->renderbuffers);
1045 /* Call the private setup routine */
1046 hr = IWineD3DSurface_PrivateSetup((IWineD3DSurface *)object);
1049 ERR("Private setup failed, returning %#x\n", hr);
1050 IWineD3DSurface_Release(*ppSurface);
1058 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
1059 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
1061 struct wined3d_rendertarget_view *object;
1063 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1066 ERR("Failed to allocate memory\n");
1067 return E_OUTOFMEMORY;
1070 object->vtbl = &wined3d_rendertarget_view_vtbl;
1071 object->refcount = 1;
1072 IWineD3DResource_AddRef(resource);
1073 object->resource = resource;
1074 object->parent = parent;
1076 *rendertarget_view = (IWineD3DRendertargetView *)object;
1081 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
1082 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
1083 WINED3DPOOL Pool, IWineD3DTexture **ppTexture, IUnknown *parent)
1085 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1086 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
1087 IWineD3DTextureImpl *object;
1092 unsigned int pow2Width;
1093 unsigned int pow2Height;
1095 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1096 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
1097 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
1099 /* TODO: It should only be possible to create textures for formats
1100 that are reported as supported */
1101 if (WINED3DFMT_UNKNOWN >= Format) {
1102 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1103 return WINED3DERR_INVALIDCALL;
1106 /* Non-power2 support */
1107 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO))
1110 pow2Height = Height;
1114 /* Find the nearest pow2 match */
1115 pow2Width = pow2Height = 1;
1116 while (pow2Width < Width) pow2Width <<= 1;
1117 while (pow2Height < Height) pow2Height <<= 1;
1119 if (pow2Width != Width || pow2Height != Height)
1123 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
1124 return WINED3DERR_INVALIDCALL;
1130 /* Calculate levels for mip mapping */
1131 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1133 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1135 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1136 return WINED3DERR_INVALIDCALL;
1141 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1142 return WINED3DERR_INVALIDCALL;
1149 Levels = wined3d_log2i(max(Width, Height)) + 1;
1150 TRACE("Calculated levels = %d\n", Levels);
1153 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1156 ERR("Out of memory\n");
1158 return WINED3DERR_OUTOFVIDEOMEMORY;
1161 object->lpVtbl = &IWineD3DTexture_Vtbl;
1162 hr = basetexture_init((IWineD3DBaseTextureImpl *)object, Levels,
1163 WINED3DRTYPE_TEXTURE, This, 0, Usage, format_desc, Pool, parent);
1166 WARN("Failed to initialize basetexture, returning %#x\n", hr);
1167 HeapFree(GetProcessHeap(), 0, object);
1172 TRACE("(%p) : Created basetexture %p\n", This, object);
1174 *ppTexture = (IWineD3DTexture *)object;
1176 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
1178 object->baseTexture.minMipLookup = minMipLookup;
1179 object->baseTexture.magLookup = magLookup;
1181 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1182 object->baseTexture.magLookup = magLookup_noFilter;
1185 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1186 /* Precalculated scaling for 'faked' non power of two texture coords.
1187 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
1188 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
1189 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
1191 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (Width != pow2Width || Height != pow2Height)) {
1192 object->baseTexture.pow2Matrix[0] = 1.0;
1193 object->baseTexture.pow2Matrix[5] = 1.0;
1194 object->baseTexture.pow2Matrix[10] = 1.0;
1195 object->baseTexture.pow2Matrix[15] = 1.0;
1196 object->target = GL_TEXTURE_2D;
1197 object->cond_np2 = TRUE;
1198 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1199 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
1200 (Width != pow2Width || Height != pow2Height) &&
1201 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
1203 if ((Width != 1) || (Height != 1)) {
1204 object->baseTexture.pow2Matrix_identity = FALSE;
1207 object->baseTexture.pow2Matrix[0] = (float)Width;
1208 object->baseTexture.pow2Matrix[5] = (float)Height;
1209 object->baseTexture.pow2Matrix[10] = 1.0;
1210 object->baseTexture.pow2Matrix[15] = 1.0;
1211 object->target = GL_TEXTURE_RECTANGLE_ARB;
1212 object->cond_np2 = TRUE;
1213 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1215 if ((Width != pow2Width) || (Height != pow2Height)) {
1216 object->baseTexture.pow2Matrix_identity = FALSE;
1217 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
1218 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
1220 object->baseTexture.pow2Matrix[0] = 1.0;
1221 object->baseTexture.pow2Matrix[5] = 1.0;
1224 object->baseTexture.pow2Matrix[10] = 1.0;
1225 object->baseTexture.pow2Matrix[15] = 1.0;
1226 object->target = GL_TEXTURE_2D;
1227 object->cond_np2 = FALSE;
1229 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
1231 /* Generate all the surfaces */
1234 for (i = 0; i < object->baseTexture.levels; i++)
1236 /* use the callback to create the texture surface */
1237 hr = IWineD3DDeviceParent_CreateSurface(This->device_parent, parent, tmpW, tmpH, Format,
1238 Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i]);
1239 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1240 FIXME("Failed to create surface %p\n", object);
1242 object->surfaces[i] = NULL;
1243 IWineD3DTexture_Release((IWineD3DTexture *)object);
1249 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1250 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1251 surface_set_texture_target(object->surfaces[i], object->target);
1252 /* calculate the next mipmap level */
1253 tmpW = max(1, tmpW >> 1);
1254 tmpH = max(1, tmpH >> 1);
1256 object->baseTexture.internal_preload = texture_internal_preload;
1258 TRACE("(%p) : Created texture %p\n", This, object);
1262 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1263 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
1264 WINED3DPOOL Pool, IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent)
1266 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1267 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
1268 IWineD3DVolumeTextureImpl *object;
1275 /* TODO: It should only be possible to create textures for formats
1276 that are reported as supported */
1277 if (WINED3DFMT_UNKNOWN >= Format) {
1278 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1279 return WINED3DERR_INVALIDCALL;
1281 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1282 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
1283 return WINED3DERR_INVALIDCALL;
1286 /* Calculate levels for mip mapping */
1287 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1289 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1291 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1292 return WINED3DERR_INVALIDCALL;
1297 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1298 return WINED3DERR_INVALIDCALL;
1305 Levels = wined3d_log2i(max(max(Width, Height), Depth)) + 1;
1306 TRACE("Calculated levels = %d\n", Levels);
1309 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1312 ERR("Out of memory\n");
1313 *ppVolumeTexture = NULL;
1314 return WINED3DERR_OUTOFVIDEOMEMORY;
1317 object->lpVtbl = &IWineD3DVolumeTexture_Vtbl;
1318 hr = basetexture_init((IWineD3DBaseTextureImpl *)object, Levels,
1319 WINED3DRTYPE_VOLUMETEXTURE, This, 0, Usage, format_desc, Pool, parent);
1322 WARN("Failed to initialize basetexture, returning %#x\n", hr);
1323 HeapFree(GetProcessHeap(), 0, object);
1324 *ppVolumeTexture = NULL;
1328 TRACE("(%p) : Created basetexture %p\n", This, object);
1330 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1331 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1333 /* Is NP2 support for volumes needed? */
1334 object->baseTexture.pow2Matrix[ 0] = 1.0;
1335 object->baseTexture.pow2Matrix[ 5] = 1.0;
1336 object->baseTexture.pow2Matrix[10] = 1.0;
1337 object->baseTexture.pow2Matrix[15] = 1.0;
1339 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
1341 object->baseTexture.minMipLookup = minMipLookup;
1342 object->baseTexture.magLookup = magLookup;
1344 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1345 object->baseTexture.magLookup = magLookup_noFilter;
1348 /* Generate all the surfaces */
1353 for (i = 0; i < object->baseTexture.levels; i++)
1356 /* Create the volume */
1357 hr = IWineD3DDeviceParent_CreateVolume(This->device_parent, parent,
1358 tmpW, tmpH, tmpD, Format, Pool, Usage, &object->volumes[i]);
1360 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
1361 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
1362 *ppVolumeTexture = NULL;
1366 /* Set its container to this object */
1367 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1369 /* calculate the next mipmap level */
1370 tmpW = max(1, tmpW >> 1);
1371 tmpH = max(1, tmpH >> 1);
1372 tmpD = max(1, tmpD >> 1);
1374 object->baseTexture.internal_preload = volumetexture_internal_preload;
1376 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1377 TRACE("(%p) : Created volume texture %p\n", This, object);
1381 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1382 UINT Width, UINT Height, UINT Depth, DWORD Usage, WINED3DFORMAT Format,
1383 WINED3DPOOL Pool, IWineD3DVolume **ppVolume, IUnknown *parent)
1385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1386 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1387 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &GLINFO_LOCATION);
1390 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1391 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1392 return WINED3DERR_INVALIDCALL;
1395 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1398 ERR("Out of memory\n");
1400 return WINED3DERR_OUTOFVIDEOMEMORY;
1403 object->lpVtbl = &IWineD3DVolume_Vtbl;
1404 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_VOLUME, This,
1405 Width * Height * Depth * format_desc->byte_count, Usage, format_desc, Pool, parent);
1408 WARN("Failed to initialize resource, returning %#x\n", hr);
1409 HeapFree(GetProcessHeap(), 0, object);
1414 TRACE("(%p) : Created resource %p\n", This, object);
1416 *ppVolume = (IWineD3DVolume *)object;
1418 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1419 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1421 object->currentDesc.Width = Width;
1422 object->currentDesc.Height = Height;
1423 object->currentDesc.Depth = Depth;
1425 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1426 object->lockable = TRUE;
1427 object->locked = FALSE;
1428 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1429 object->dirty = TRUE;
1431 volume_add_dirty_box((IWineD3DVolume *)object, NULL);
1436 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface,
1437 UINT EdgeLength, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
1438 WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture, IUnknown *parent)
1440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1441 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
1442 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1446 unsigned int pow2EdgeLength;
1448 /* TODO: It should only be possible to create textures for formats
1449 that are reported as supported */
1450 if (WINED3DFMT_UNKNOWN >= Format) {
1451 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1452 return WINED3DERR_INVALIDCALL;
1455 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1456 WARN("(%p) : Tried to create not supported cube texture\n", This);
1457 return WINED3DERR_INVALIDCALL;
1460 /* Calculate levels for mip mapping */
1461 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1463 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1465 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1466 return WINED3DERR_INVALIDCALL;
1471 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1472 return WINED3DERR_INVALIDCALL;
1479 Levels = wined3d_log2i(EdgeLength) + 1;
1480 TRACE("Calculated levels = %d\n", Levels);
1483 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1486 ERR("Out of memory\n");
1487 *ppCubeTexture = NULL;
1488 return WINED3DERR_OUTOFVIDEOMEMORY;
1491 object->lpVtbl = &IWineD3DCubeTexture_Vtbl;
1492 hr = basetexture_init((IWineD3DBaseTextureImpl *)object, Levels,
1493 WINED3DRTYPE_CUBETEXTURE, This, 0, Usage, format_desc, Pool, parent);
1496 WARN("Failed to initialize basetexture, returning %#x\n", hr);
1497 HeapFree(GetProcessHeap(), 0, object);
1498 *ppCubeTexture = NULL;
1502 TRACE("(%p) : Created basetexture %p\n", This, object);
1504 TRACE("(%p) Create Cube Texture\n", This);
1506 /* Find the nearest pow2 match */
1508 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1510 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || (EdgeLength == pow2EdgeLength)) {
1511 /* Precalculated scaling for 'faked' non power of two texture coords */
1512 object->baseTexture.pow2Matrix[ 0] = 1.0;
1513 object->baseTexture.pow2Matrix[ 5] = 1.0;
1514 object->baseTexture.pow2Matrix[10] = 1.0;
1515 object->baseTexture.pow2Matrix[15] = 1.0;
1517 /* Precalculated scaling for 'faked' non power of two texture coords */
1518 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1519 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1520 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1521 object->baseTexture.pow2Matrix[15] = 1.0;
1522 object->baseTexture.pow2Matrix_identity = FALSE;
1525 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
1527 object->baseTexture.minMipLookup = minMipLookup;
1528 object->baseTexture.magLookup = magLookup;
1530 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1531 object->baseTexture.magLookup = magLookup_noFilter;
1534 /* Generate all the surfaces */
1536 for (i = 0; i < object->baseTexture.levels; i++) {
1538 /* Create the 6 faces */
1539 for (j = 0; j < 6; j++) {
1540 static const GLenum cube_targets[6] = {
1541 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
1542 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
1543 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
1544 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
1545 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
1546 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
1549 hr = IWineD3DDeviceParent_CreateSurface(This->device_parent, parent, tmpW, tmpW,
1550 Format, Usage, Pool, i /* Level */, j, &object->surfaces[j][i]);
1553 FIXME("(%p) Failed to create surface\n",object);
1554 IWineD3DCubeTexture_Release((IWineD3DCubeTexture *)object);
1555 *ppCubeTexture = NULL;
1558 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1559 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1560 surface_set_texture_target(object->surfaces[j][i], cube_targets[j]);
1562 tmpW = max(1, tmpW >> 1);
1564 object->baseTexture.internal_preload = cubetexture_internal_preload;
1566 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1567 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1571 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1572 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1573 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1574 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1575 const IWineD3DQueryVtbl *vtable;
1577 /* Just a check to see if we support this type of query */
1579 case WINED3DQUERYTYPE_OCCLUSION:
1580 TRACE("(%p) occlusion query\n", This);
1581 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1584 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1586 vtable = &IWineD3DOcclusionQuery_Vtbl;
1589 case WINED3DQUERYTYPE_EVENT:
1590 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1591 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1592 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1594 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1596 vtable = &IWineD3DEventQuery_Vtbl;
1600 case WINED3DQUERYTYPE_VCACHE:
1601 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1602 case WINED3DQUERYTYPE_VERTEXSTATS:
1603 case WINED3DQUERYTYPE_TIMESTAMP:
1604 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1605 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1606 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1607 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1608 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1609 case WINED3DQUERYTYPE_PIXELTIMINGS:
1610 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1611 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1613 /* Use the base Query vtable until we have a special one for each query */
1614 vtable = &IWineD3DQuery_Vtbl;
1615 FIXME("(%p) Unhandled query type %d\n", This, Type);
1617 if(NULL == ppQuery || hr != WINED3D_OK) {
1621 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1624 ERR("Out of memory\n");
1626 return WINED3DERR_OUTOFVIDEOMEMORY;
1629 object->lpVtbl = vtable;
1630 object->type = Type;
1631 object->state = QUERY_CREATED;
1632 object->wineD3DDevice = This;
1633 object->parent = parent;
1636 *ppQuery = (IWineD3DQuery *)object;
1638 /* allocated the 'extended' data based on the type of query requested */
1640 case WINED3DQUERYTYPE_OCCLUSION:
1641 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1642 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1644 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1645 TRACE("(%p) Allocating data for an occlusion query\n", This);
1647 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1649 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1653 case WINED3DQUERYTYPE_EVENT:
1654 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1655 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1657 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1659 if(GL_SUPPORT(APPLE_FENCE)) {
1660 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1661 checkGLcall("glGenFencesAPPLE");
1662 } else if(GL_SUPPORT(NV_FENCE)) {
1663 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1664 checkGLcall("glGenFencesNV");
1669 case WINED3DQUERYTYPE_VCACHE:
1670 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1671 case WINED3DQUERYTYPE_VERTEXSTATS:
1672 case WINED3DQUERYTYPE_TIMESTAMP:
1673 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1674 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1675 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1676 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1677 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1678 case WINED3DQUERYTYPE_PIXELTIMINGS:
1679 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1680 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1682 object->extendedData = 0;
1683 FIXME("(%p) Unhandled query type %d\n",This , Type);
1685 TRACE("(%p) : Created Query %p\n", This, object);
1689 /*****************************************************************************
1690 * IWineD3DDeviceImpl_SetupFullscreenWindow
1692 * Helper function that modifies a HWND's Style and ExStyle for proper
1696 * iface: Pointer to the IWineD3DDevice interface
1697 * window: Window to setup
1699 *****************************************************************************/
1700 static LONG fullscreen_style(LONG orig_style) {
1701 LONG style = orig_style;
1702 style &= ~WS_CAPTION;
1703 style &= ~WS_THICKFRAME;
1705 /* Make sure the window is managed, otherwise we won't get keyboard input */
1706 style |= WS_POPUP | WS_SYSMENU;
1711 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1712 LONG exStyle = orig_exStyle;
1714 /* Filter out window decorations */
1715 exStyle &= ~WS_EX_WINDOWEDGE;
1716 exStyle &= ~WS_EX_CLIENTEDGE;
1721 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1722 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1724 LONG style, exStyle;
1725 /* Don't do anything if an original style is stored.
1726 * That shouldn't happen
1728 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1729 if (This->style || This->exStyle) {
1730 ERR("(%p): Want to change the window parameters of HWND %p, but "
1731 "another style is stored for restoration afterwards\n", This, window);
1734 /* Get the parameters and save them */
1735 style = GetWindowLongW(window, GWL_STYLE);
1736 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1737 This->style = style;
1738 This->exStyle = exStyle;
1740 style = fullscreen_style(style);
1741 exStyle = fullscreen_exStyle(exStyle);
1743 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1744 This->style, This->exStyle, style, exStyle);
1746 SetWindowLongW(window, GWL_STYLE, style);
1747 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1749 /* Inform the window about the update. */
1750 SetWindowPos(window, HWND_TOP, 0, 0,
1751 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1754 /*****************************************************************************
1755 * IWineD3DDeviceImpl_RestoreWindow
1757 * Helper function that restores a windows' properties when taking it out
1758 * of fullscreen mode
1761 * iface: Pointer to the IWineD3DDevice interface
1762 * window: Window to setup
1764 *****************************************************************************/
1765 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1766 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1767 LONG style, exStyle;
1769 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1770 * switch, do nothing
1772 if (!This->style && !This->exStyle) return;
1774 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1775 This, window, This->style, This->exStyle);
1777 style = GetWindowLongW(window, GWL_STYLE);
1778 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1780 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1781 * Some applications change it before calling Reset() when switching between windowed and
1782 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1784 if(style == fullscreen_style(This->style) &&
1785 exStyle == fullscreen_style(This->exStyle)) {
1786 SetWindowLongW(window, GWL_STYLE, This->style);
1787 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1790 /* Delete the old values */
1794 /* Inform the window about the update */
1795 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1796 0, 0, 0, 0, /* Pos, Size, ignored */
1797 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1800 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1801 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1802 WINED3DPRESENT_PARAMETERS *pPresentationParameters, IWineD3DSwapChain **ppSwapChain,
1803 IUnknown *parent, WINED3DSURFTYPE surface_type)
1805 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1808 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1810 IUnknown *bufferParent;
1811 BOOL displaymode_set = FALSE;
1812 WINED3DDISPLAYMODE Mode;
1813 const struct GlPixelFormatDesc *format_desc;
1815 TRACE("(%p) : Created Additional Swap Chain\n", This);
1817 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1818 * does a device hold a reference to a swap chain giving them a lifetime of the device
1819 * or does the swap chain notify the device of its destruction.
1820 *******************************/
1822 /* Check the params */
1823 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1824 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1825 return WINED3DERR_INVALIDCALL;
1826 } else if (pPresentationParameters->BackBufferCount > 1) {
1827 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");
1830 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1833 ERR("Out of memory\n");
1834 *ppSwapChain = NULL;
1835 return WINED3DERR_OUTOFVIDEOMEMORY;
1838 switch(surface_type) {
1840 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1842 case SURFACE_OPENGL:
1843 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1845 case SURFACE_UNKNOWN:
1846 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1847 HeapFree(GetProcessHeap(), 0, object);
1848 return WINED3DERR_INVALIDCALL;
1850 object->wineD3DDevice = This;
1851 object->parent = parent;
1854 *ppSwapChain = (IWineD3DSwapChain *)object;
1856 /*********************
1857 * Lookup the window Handle and the relating X window handle
1858 ********************/
1860 /* Setup hwnd we are using, plus which display this equates to */
1861 object->win_handle = pPresentationParameters->hDeviceWindow;
1862 if (!object->win_handle) {
1863 object->win_handle = This->createParms.hFocusWindow;
1865 if(!pPresentationParameters->Windowed && object->win_handle) {
1866 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1867 pPresentationParameters->BackBufferWidth,
1868 pPresentationParameters->BackBufferHeight);
1871 hDc = GetDC(object->win_handle);
1872 TRACE("Using hDc %p\n", hDc);
1875 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1876 return WINED3DERR_NOTAVAILABLE;
1879 /* Get info on the current display setup */
1880 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1881 object->orig_width = Mode.Width;
1882 object->orig_height = Mode.Height;
1883 object->orig_fmt = Mode.Format;
1884 format_desc = getFormatDescEntry(Mode.Format, &GLINFO_LOCATION);
1886 if (pPresentationParameters->Windowed &&
1887 ((pPresentationParameters->BackBufferWidth == 0) ||
1888 (pPresentationParameters->BackBufferHeight == 0) ||
1889 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1892 GetClientRect(object->win_handle, &Rect);
1894 if (pPresentationParameters->BackBufferWidth == 0) {
1895 pPresentationParameters->BackBufferWidth = Rect.right;
1896 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1898 if (pPresentationParameters->BackBufferHeight == 0) {
1899 pPresentationParameters->BackBufferHeight = Rect.bottom;
1900 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1902 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1903 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1904 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1908 /* Put the correct figures in the presentation parameters */
1909 TRACE("Copying across presentation parameters\n");
1910 object->presentParms = *pPresentationParameters;
1912 TRACE("calling rendertarget CB\n");
1913 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1914 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1915 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1916 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->frontBuffer);
1917 if (SUCCEEDED(hr)) {
1918 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1919 ((IWineD3DSurfaceImpl *)object->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
1920 if(surface_type == SURFACE_OPENGL) {
1921 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1924 ERR("Failed to create the front buffer\n");
1928 /*********************
1929 * Windowed / Fullscreen
1930 *******************/
1933 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1934 * so we should really check to see if there is a fullscreen swapchain already
1935 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1936 **************************************/
1938 if (!pPresentationParameters->Windowed) {
1939 WINED3DDISPLAYMODE mode;
1942 /* Change the display settings */
1943 mode.Width = pPresentationParameters->BackBufferWidth;
1944 mode.Height = pPresentationParameters->BackBufferHeight;
1945 mode.Format = pPresentationParameters->BackBufferFormat;
1946 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1948 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1949 displaymode_set = TRUE;
1953 * Create an opengl context for the display visual
1954 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1955 * use different properties after that point in time. FIXME: How to handle when requested format
1956 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1957 * it chooses is identical to the one already being used!
1958 **********************************/
1959 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1961 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1962 if(!object->context) {
1963 ERR("Failed to create the context array\n");
1967 object->num_contexts = 1;
1969 if(surface_type == SURFACE_OPENGL) {
1970 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1971 if (!object->context[0]) {
1972 ERR("Failed to create a new context\n");
1973 hr = WINED3DERR_NOTAVAILABLE;
1976 TRACE("Context created (HWND=%p, glContext=%p)\n",
1977 object->win_handle, object->context[0]->glCtx);
1981 /*********************
1982 * Create the back, front and stencil buffers
1983 *******************/
1984 if(object->presentParms.BackBufferCount > 0) {
1987 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1988 if(!object->backBuffer) {
1989 ERR("Out of memory\n");
1994 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1995 TRACE("calling rendertarget CB\n");
1996 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1997 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1998 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1999 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->backBuffer[i]);
2001 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
2002 ((IWineD3DSurfaceImpl *)object->backBuffer[i])->Flags |= SFLAG_SWAPCHAIN;
2004 ERR("Cannot create new back buffer\n");
2007 if(surface_type == SURFACE_OPENGL) {
2009 glDrawBuffer(GL_BACK);
2010 checkGLcall("glDrawBuffer(GL_BACK)");
2015 object->backBuffer = NULL;
2017 /* Single buffering - draw to front buffer */
2018 if(surface_type == SURFACE_OPENGL) {
2020 glDrawBuffer(GL_FRONT);
2021 checkGLcall("glDrawBuffer(GL_FRONT)");
2026 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
2027 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
2028 TRACE("Creating depth stencil buffer\n");
2029 if (This->auto_depth_stencil_buffer == NULL ) {
2030 hr = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent, parent,
2031 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
2032 object->presentParms.AutoDepthStencilFormat, object->presentParms.MultiSampleType,
2033 object->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */,
2034 &This->auto_depth_stencil_buffer);
2035 if (SUCCEEDED(hr)) {
2036 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
2038 ERR("Failed to create the auto depth stencil\n");
2044 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
2046 TRACE("Created swapchain %p\n", object);
2047 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
2051 if (displaymode_set) {
2055 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
2058 /* Change the display settings */
2059 memset(&devmode, 0, sizeof(devmode));
2060 devmode.dmSize = sizeof(devmode);
2061 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2062 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2063 devmode.dmPelsWidth = object->orig_width;
2064 devmode.dmPelsHeight = object->orig_height;
2065 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
2068 if (object->backBuffer) {
2070 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
2071 if(object->backBuffer[i]) {
2072 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
2073 IUnknown_Release(bufferParent); /* once for the get parent */
2074 if (IUnknown_Release(bufferParent) > 0) {
2075 FIXME("(%p) Something's still holding the back buffer\n",This);
2079 HeapFree(GetProcessHeap(), 0, object->backBuffer);
2080 object->backBuffer = NULL;
2082 if(object->context && object->context[0])
2083 DestroyContext(This, object->context[0]);
2084 if(object->frontBuffer) {
2085 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
2086 IUnknown_Release(bufferParent); /* once for the get parent */
2087 if (IUnknown_Release(bufferParent) > 0) {
2088 FIXME("(%p) Something's still holding the front buffer\n",This);
2091 HeapFree(GetProcessHeap(), 0, object);
2095 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
2096 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
2097 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2098 TRACE("(%p)\n", This);
2100 return This->NumberOfSwapChains;
2103 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
2104 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2105 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
2107 if(iSwapChain < This->NumberOfSwapChains) {
2108 *pSwapChain = This->swapchains[iSwapChain];
2109 IWineD3DSwapChain_AddRef(*pSwapChain);
2110 TRACE("(%p) returning %p\n", This, *pSwapChain);
2113 TRACE("Swapchain out of range\n");
2115 return WINED3DERR_INVALIDCALL;
2120 * Vertex Declaration
2122 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
2123 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
2124 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2125 IWineD3DVertexDeclarationImpl *object = NULL;
2126 HRESULT hr = WINED3D_OK;
2128 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
2129 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
2131 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2134 ERR("Out of memory\n");
2135 *ppVertexDeclaration = NULL;
2136 return WINED3DERR_OUTOFVIDEOMEMORY;
2139 object->lpVtbl = &IWineD3DVertexDeclaration_Vtbl;
2140 object->wineD3DDevice = This;
2141 object->parent = parent;
2144 *ppVertexDeclaration = (IWineD3DVertexDeclaration *)object;
2146 hr = vertexdeclaration_init(object, elements, element_count);
2149 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
2150 *ppVertexDeclaration = NULL;
2156 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
2157 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
2159 unsigned int idx, idx2;
2160 unsigned int offset;
2161 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
2162 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
2163 BOOL has_blend_idx = has_blend &&
2164 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
2165 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
2166 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
2167 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
2168 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
2169 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
2170 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
2172 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
2173 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
2174 WINED3DVERTEXELEMENT *elements = NULL;
2177 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
2178 if (has_blend_idx) num_blends--;
2180 /* Compute declaration size */
2181 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
2182 has_psize + has_diffuse + has_specular + num_textures;
2184 /* convert the declaration */
2185 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
2186 if (!elements) return ~0U;
2190 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
2191 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
2192 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
2194 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
2195 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
2196 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
2199 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
2200 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
2202 elements[idx].usage_idx = 0;
2205 if (has_blend && (num_blends > 0)) {
2206 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
2207 elements[idx].format = WINED3DFMT_A8R8G8B8;
2209 switch(num_blends) {
2210 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
2211 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
2212 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
2213 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
2215 ERR("Unexpected amount of blend values: %u\n", num_blends);
2218 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
2219 elements[idx].usage_idx = 0;
2222 if (has_blend_idx) {
2223 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
2224 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
2225 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
2226 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
2227 elements[idx].format = WINED3DFMT_A8R8G8B8;
2229 elements[idx].format = WINED3DFMT_R32_FLOAT;
2230 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
2231 elements[idx].usage_idx = 0;
2235 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
2236 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
2237 elements[idx].usage_idx = 0;
2241 elements[idx].format = WINED3DFMT_R32_FLOAT;
2242 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
2243 elements[idx].usage_idx = 0;
2247 elements[idx].format = WINED3DFMT_A8R8G8B8;
2248 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
2249 elements[idx].usage_idx = 0;
2253 elements[idx].format = WINED3DFMT_A8R8G8B8;
2254 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
2255 elements[idx].usage_idx = 1;
2258 for (idx2 = 0; idx2 < num_textures; idx2++) {
2259 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
2260 switch (numcoords) {
2261 case WINED3DFVF_TEXTUREFORMAT1:
2262 elements[idx].format = WINED3DFMT_R32_FLOAT;
2264 case WINED3DFVF_TEXTUREFORMAT2:
2265 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
2267 case WINED3DFVF_TEXTUREFORMAT3:
2268 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
2270 case WINED3DFVF_TEXTUREFORMAT4:
2271 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
2274 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
2275 elements[idx].usage_idx = idx2;
2279 /* Now compute offsets, and initialize the rest of the fields */
2280 for (idx = 0, offset = 0; idx < size; ++idx)
2282 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
2283 elements[idx].input_slot = 0;
2284 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
2285 elements[idx].offset = offset;
2286 offset += format_desc->component_count * format_desc->component_size;
2289 *ppVertexElements = elements;
2293 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
2294 WINED3DVERTEXELEMENT* elements = NULL;
2295 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2299 size = ConvertFvfToDeclaration(This, Fvf, &elements);
2300 if (size == ~0U) return WINED3DERR_OUTOFVIDEOMEMORY;
2302 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
2303 HeapFree(GetProcessHeap(), 0, elements);
2304 if (hr != S_OK) return hr;
2309 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
2310 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
2311 IWineD3DVertexShader **ppVertexShader, IUnknown *parent)
2313 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2314 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
2315 HRESULT hr = WINED3D_OK;
2317 if (!pFunction) return WINED3DERR_INVALIDCALL;
2319 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2322 ERR("Out of memory\n");
2323 *ppVertexShader = NULL;
2324 return WINED3DERR_OUTOFVIDEOMEMORY;
2327 object->lpVtbl = &IWineD3DVertexShader_Vtbl;
2328 object->parent = parent;
2329 shader_init(&object->baseShader, iface);
2330 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2331 *ppVertexShader = (IWineD3DVertexShader *)object;
2333 TRACE("(%p) : Created vertex shader %p\n", This, *ppVertexShader);
2335 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction, output_signature);
2338 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2339 IWineD3DVertexShader_Release(*ppVertexShader);
2340 *ppVertexShader = NULL;
2347 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
2348 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
2349 IWineD3DPixelShader **ppPixelShader, IUnknown *parent)
2351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2352 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
2353 HRESULT hr = WINED3D_OK;
2355 if (!pFunction) return WINED3DERR_INVALIDCALL;
2357 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2360 ERR("Out of memory\n");
2361 *ppPixelShader = NULL;
2362 return WINED3DERR_OUTOFVIDEOMEMORY;
2365 object->lpVtbl = &IWineD3DPixelShader_Vtbl;
2366 object->parent = parent;
2367 shader_init(&object->baseShader, iface);
2368 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2369 *ppPixelShader = (IWineD3DPixelShader *)object;
2371 TRACE("(%p) : Created pixel shader %p\n", This, *ppPixelShader);
2373 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction, output_signature);
2376 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2377 IWineD3DPixelShader_Release(*ppPixelShader);
2378 *ppPixelShader = NULL;
2385 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
2386 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
2388 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2389 IWineD3DPaletteImpl *object;
2391 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
2393 /* Create the new object */
2394 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
2396 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
2397 return E_OUTOFMEMORY;
2400 object->lpVtbl = &IWineD3DPalette_Vtbl;
2402 object->Flags = Flags;
2403 object->parent = Parent;
2404 object->wineD3DDevice = This;
2405 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2406 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2409 HeapFree( GetProcessHeap(), 0, object);
2410 return E_OUTOFMEMORY;
2413 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2415 IWineD3DPalette_Release((IWineD3DPalette *) object);
2419 *Palette = (IWineD3DPalette *) object;
2424 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
2428 HDC dcb = NULL, dcs = NULL;
2429 WINEDDCOLORKEY colorkey;
2431 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
2434 GetObjectA(hbm, sizeof(BITMAP), &bm);
2435 dcb = CreateCompatibleDC(NULL);
2437 SelectObject(dcb, hbm);
2441 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
2442 * couldn't be loaded
2444 memset(&bm, 0, sizeof(bm));
2449 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
2450 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
2451 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL, NULL);
2453 ERR("Wine logo requested, but failed to create surface\n");
2458 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
2459 if(FAILED(hr)) goto out;
2460 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
2461 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
2463 colorkey.dwColorSpaceLowValue = 0;
2464 colorkey.dwColorSpaceHighValue = 0;
2465 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2467 /* Fill the surface with a white color to show that wined3d is there */
2468 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2481 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2483 /* Under DirectX you can have texture stage operations even if no texture is
2484 bound, whereas opengl will only do texture operations when a valid texture is
2485 bound. We emulate this by creating dummy textures and binding them to each
2486 texture stage, but disable all stages by default. Hence if a stage is enabled
2487 then the default texture will kick in until replaced by a SetTexture call */
2490 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2491 /* The dummy texture does not have client storage backing */
2492 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2493 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2495 for (i = 0; i < GL_LIMITS(textures); i++) {
2496 GLubyte white = 255;
2498 /* Make appropriate texture active */
2499 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2500 checkGLcall("glActiveTextureARB");
2502 /* Generate an opengl texture name */
2503 glGenTextures(1, &This->dummyTextureName[i]);
2504 checkGLcall("glGenTextures");
2505 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2507 /* Generate a dummy 2d texture (not using 1d because they cause many
2508 * DRI drivers fall back to sw) */
2509 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2510 checkGLcall("glBindTexture");
2512 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2513 checkGLcall("glTexImage2D");
2515 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2516 /* Reenable because if supported it is enabled by default */
2517 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2518 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2524 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
2525 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2528 IWineD3DSwapChainImpl *swapchain = NULL;
2533 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
2535 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2536 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2538 /* TODO: Test if OpenGL is compiled in and loaded */
2540 TRACE("(%p) : Creating stateblock\n", This);
2541 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2542 hr = IWineD3DDevice_CreateStateBlock(iface,
2544 (IWineD3DStateBlock **)&This->stateBlock,
2546 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2547 WARN("Failed to create stateblock\n");
2550 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2551 This->updateStateBlock = This->stateBlock;
2552 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2554 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2555 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2557 This->NumberOfPalettes = 1;
2558 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2559 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2560 ERR("Out of memory!\n");
2563 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2564 if(!This->palettes[0]) {
2565 ERR("Out of memory!\n");
2568 for (i = 0; i < 256; ++i) {
2569 This->palettes[0][i].peRed = 0xFF;
2570 This->palettes[0][i].peGreen = 0xFF;
2571 This->palettes[0][i].peBlue = 0xFF;
2572 This->palettes[0][i].peFlags = 0xFF;
2574 This->currentPalette = 0;
2576 /* Initialize the texture unit mapping to a 1:1 mapping */
2577 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2578 if (state < GL_LIMITS(fragment_samplers)) {
2579 This->texUnitMap[state] = state;
2580 This->rev_tex_unit_map[state] = state;
2582 This->texUnitMap[state] = -1;
2583 This->rev_tex_unit_map[state] = -1;
2587 /* Setup the implicit swapchain */
2588 TRACE("Creating implicit swapchain\n");
2589 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2590 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2593 WARN("Failed to create implicit swapchain\n");
2597 This->NumberOfSwapChains = 1;
2598 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2599 if(!This->swapchains) {
2600 ERR("Out of memory!\n");
2603 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2605 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2606 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2607 This->render_targets[0] = swapchain->backBuffer[0];
2608 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2611 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2612 This->render_targets[0] = swapchain->frontBuffer;
2613 This->lastActiveRenderTarget = swapchain->frontBuffer;
2615 IWineD3DSurface_AddRef(This->render_targets[0]);
2616 This->activeContext = swapchain->context[0];
2617 This->lastThread = GetCurrentThreadId();
2619 /* Depth Stencil support */
2620 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2621 if (NULL != This->stencilBufferTarget) {
2622 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2625 hr = This->shader_backend->shader_alloc_private(iface);
2627 TRACE("Shader private data couldn't be allocated\n");
2630 hr = This->frag_pipe->alloc_private(iface);
2632 TRACE("Fragment pipeline private data couldn't be allocated\n");
2635 hr = This->blitter->alloc_private(iface);
2637 TRACE("Blitter private data couldn't be allocated\n");
2641 /* Set up some starting GL setup */
2643 /* Setup all the devices defaults */
2644 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2645 create_dummy_textures(This);
2649 /* Initialize the current view state */
2650 This->view_ident = 1;
2651 This->contexts[0]->last_was_rhw = 0;
2652 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2653 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2655 switch(wined3d_settings.offscreen_rendering_mode) {
2658 This->offscreenBuffer = GL_BACK;
2661 case ORM_BACKBUFFER:
2663 if(This->activeContext->aux_buffers > 0) {
2664 TRACE("Using auxilliary buffer for offscreen rendering\n");
2665 This->offscreenBuffer = GL_AUX0;
2667 TRACE("Using back buffer for offscreen rendering\n");
2668 This->offscreenBuffer = GL_BACK;
2673 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2676 /* Clear the screen */
2677 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2678 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2681 This->d3d_initialized = TRUE;
2683 if(wined3d_settings.logo) {
2684 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2686 This->highest_dirty_ps_const = 0;
2687 This->highest_dirty_vs_const = 0;
2691 HeapFree(GetProcessHeap(), 0, This->render_targets);
2692 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2693 HeapFree(GetProcessHeap(), 0, This->swapchains);
2694 This->NumberOfSwapChains = 0;
2695 if(This->palettes) {
2696 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2697 HeapFree(GetProcessHeap(), 0, This->palettes);
2699 This->NumberOfPalettes = 0;
2701 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2703 if(This->stateBlock) {
2704 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2705 This->stateBlock = NULL;
2707 if (This->blit_priv) {
2708 This->blitter->free_private(iface);
2710 if (This->fragment_priv) {
2711 This->frag_pipe->free_private(iface);
2713 if (This->shader_priv) {
2714 This->shader_backend->shader_free_private(iface);
2719 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2720 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2722 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2723 IWineD3DSwapChainImpl *swapchain = NULL;
2726 /* Setup the implicit swapchain */
2727 TRACE("Creating implicit swapchain\n");
2728 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2729 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2732 WARN("Failed to create implicit swapchain\n");
2736 This->NumberOfSwapChains = 1;
2737 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2738 if(!This->swapchains) {
2739 ERR("Out of memory!\n");
2742 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2746 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2750 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2752 IWineD3DResource_UnLoad(resource);
2753 IWineD3DResource_Release(resource);
2757 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2758 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2761 TRACE("(%p)\n", This);
2763 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2765 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2766 * it was created. Thus make sure a context is active for the glDelete* calls
2768 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2770 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2772 /* Unload resources */
2773 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2775 TRACE("Deleting high order patches\n");
2776 for(i = 0; i < PATCHMAP_SIZE; i++) {
2777 struct list *e1, *e2;
2778 struct WineD3DRectPatch *patch;
2779 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2780 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2781 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2785 /* Delete the palette conversion shader if it is around */
2786 if(This->paletteConversionShader) {
2788 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2790 This->paletteConversionShader = 0;
2793 /* Delete the pbuffer context if there is any */
2794 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2796 /* Delete the mouse cursor texture */
2797 if(This->cursorTexture) {
2799 glDeleteTextures(1, &This->cursorTexture);
2801 This->cursorTexture = 0;
2804 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2805 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2807 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2808 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2811 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2812 * private data, it might contain opengl pointers
2814 if(This->depth_blt_texture) {
2816 glDeleteTextures(1, &This->depth_blt_texture);
2818 This->depth_blt_texture = 0;
2820 if (This->depth_blt_rb) {
2822 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2824 This->depth_blt_rb = 0;
2825 This->depth_blt_rb_w = 0;
2826 This->depth_blt_rb_h = 0;
2829 /* Release the update stateblock */
2830 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2831 if(This->updateStateBlock != This->stateBlock)
2832 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2834 This->updateStateBlock = NULL;
2836 { /* because were not doing proper internal refcounts releasing the primary state block
2837 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2838 to set this->stateBlock = NULL; first */
2839 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2840 This->stateBlock = NULL;
2842 /* Release the stateblock */
2843 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2844 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2848 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2849 This->blitter->free_private(iface);
2850 This->frag_pipe->free_private(iface);
2851 This->shader_backend->shader_free_private(iface);
2853 /* Release the buffers (with sanity checks)*/
2854 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2855 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2856 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2857 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2859 This->stencilBufferTarget = NULL;
2861 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2862 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2863 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2865 TRACE("Setting rendertarget to NULL\n");
2866 This->render_targets[0] = NULL;
2868 if (This->auto_depth_stencil_buffer) {
2869 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2870 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2872 This->auto_depth_stencil_buffer = NULL;
2875 for(i=0; i < This->NumberOfSwapChains; i++) {
2876 TRACE("Releasing the implicit swapchain %d\n", i);
2877 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2878 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2882 HeapFree(GetProcessHeap(), 0, This->swapchains);
2883 This->swapchains = NULL;
2884 This->NumberOfSwapChains = 0;
2886 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2887 HeapFree(GetProcessHeap(), 0, This->palettes);
2888 This->palettes = NULL;
2889 This->NumberOfPalettes = 0;
2891 HeapFree(GetProcessHeap(), 0, This->render_targets);
2892 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2893 This->render_targets = NULL;
2894 This->draw_buffers = NULL;
2896 This->d3d_initialized = FALSE;
2900 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2901 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2904 for(i=0; i < This->NumberOfSwapChains; i++) {
2905 TRACE("Releasing the implicit swapchain %d\n", i);
2906 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2907 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2911 HeapFree(GetProcessHeap(), 0, This->swapchains);
2912 This->swapchains = NULL;
2913 This->NumberOfSwapChains = 0;
2917 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2918 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2919 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2921 * There is no way to deactivate thread safety once it is enabled.
2923 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2924 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2926 /*For now just store the flag(needed in case of ddraw) */
2927 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2932 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2933 const WINED3DDISPLAYMODE* pMode) {
2935 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2937 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &GLINFO_LOCATION);
2940 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2942 /* Resize the screen even without a window:
2943 * The app could have unset it with SetCooperativeLevel, but not called
2944 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2945 * but we don't have any hwnd
2948 memset(&devmode, 0, sizeof(devmode));
2949 devmode.dmSize = sizeof(devmode);
2950 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2951 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2952 devmode.dmPelsWidth = pMode->Width;
2953 devmode.dmPelsHeight = pMode->Height;
2955 devmode.dmDisplayFrequency = pMode->RefreshRate;
2956 if (pMode->RefreshRate != 0) {
2957 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2960 /* Only change the mode if necessary */
2961 if( (This->ddraw_width == pMode->Width) &&
2962 (This->ddraw_height == pMode->Height) &&
2963 (This->ddraw_format == pMode->Format) &&
2964 (pMode->RefreshRate == 0) ) {
2968 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2969 if (ret != DISP_CHANGE_SUCCESSFUL) {
2970 if(devmode.dmDisplayFrequency != 0) {
2971 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2972 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2973 devmode.dmDisplayFrequency = 0;
2974 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2976 if(ret != DISP_CHANGE_SUCCESSFUL) {
2977 return WINED3DERR_NOTAVAILABLE;
2981 /* Store the new values */
2982 This->ddraw_width = pMode->Width;
2983 This->ddraw_height = pMode->Height;
2984 This->ddraw_format = pMode->Format;
2986 /* And finally clip mouse to our screen */
2987 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2988 ClipCursor(&clip_rc);
2993 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2994 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2995 *ppD3D= This->wineD3D;
2996 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2997 IWineD3D_AddRef(*ppD3D);
3001 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
3002 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3004 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
3005 (This->adapter->TextureRam/(1024*1024)),
3006 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
3007 /* return simulated texture memory left */
3008 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
3012 * Get / Set Stream Source
3014 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
3015 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
3017 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3018 IWineD3DBuffer *oldSrc;
3020 if (StreamNumber >= MAX_STREAMS) {
3021 WARN("Stream out of range %d\n", StreamNumber);
3022 return WINED3DERR_INVALIDCALL;
3023 } else if(OffsetInBytes & 0x3) {
3024 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
3025 return WINED3DERR_INVALIDCALL;
3028 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
3029 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
3031 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
3033 if(oldSrc == pStreamData &&
3034 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
3035 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
3036 TRACE("Application is setting the old values over, nothing to do\n");
3040 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
3042 This->updateStateBlock->streamStride[StreamNumber] = Stride;
3043 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
3046 /* Handle recording of state blocks */
3047 if (This->isRecordingState) {
3048 TRACE("Recording... not performing anything\n");
3049 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
3050 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
3054 if (pStreamData != NULL) {
3055 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
3056 IWineD3DBuffer_AddRef(pStreamData);
3058 if (oldSrc != NULL) {
3059 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
3060 IWineD3DBuffer_Release(oldSrc);
3063 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3068 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
3069 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
3071 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3073 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
3074 This->stateBlock->streamSource[StreamNumber],
3075 This->stateBlock->streamOffset[StreamNumber],
3076 This->stateBlock->streamStride[StreamNumber]);
3078 if (StreamNumber >= MAX_STREAMS) {
3079 WARN("Stream out of range %d\n", StreamNumber);
3080 return WINED3DERR_INVALIDCALL;
3082 *pStream = This->stateBlock->streamSource[StreamNumber];
3083 *pStride = This->stateBlock->streamStride[StreamNumber];
3085 *pOffset = This->stateBlock->streamOffset[StreamNumber];
3088 if (*pStream != NULL) {
3089 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
3094 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
3095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3096 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
3097 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
3099 /* Verify input at least in d3d9 this is invalid*/
3100 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
3101 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
3102 return WINED3DERR_INVALIDCALL;
3104 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
3105 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
3106 return WINED3DERR_INVALIDCALL;
3109 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
3110 return WINED3DERR_INVALIDCALL;
3113 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
3114 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
3116 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
3117 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
3119 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
3120 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
3121 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3127 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
3128 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3130 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
3131 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
3133 TRACE("(%p) : returning %d\n", This, *Divider);
3139 * Get / Set & Multiply Transform
3141 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
3142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3144 /* Most of this routine, comments included copied from ddraw tree initially: */
3145 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
3147 /* Handle recording of state blocks */
3148 if (This->isRecordingState) {
3149 TRACE("Recording... not performing anything\n");
3150 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
3151 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
3156 * If the new matrix is the same as the current one,
3157 * we cut off any further processing. this seems to be a reasonable
3158 * optimization because as was noticed, some apps (warcraft3 for example)
3159 * tend towards setting the same matrix repeatedly for some reason.
3161 * From here on we assume that the new matrix is different, wherever it matters.
3163 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
3164 TRACE("The app is setting the same matrix over again\n");
3167 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
3171 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
3172 where ViewMat = Camera space, WorldMat = world space.
3174 In OpenGL, camera and world space is combined into GL_MODELVIEW
3175 matrix. The Projection matrix stay projection matrix.
3178 /* Capture the times we can just ignore the change for now */
3179 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
3180 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
3181 /* Handled by the state manager */
3184 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
3188 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
3189 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3190 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
3191 *pMatrix = This->stateBlock->transforms[State];
3195 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
3196 const WINED3DMATRIX *mat = NULL;
3199 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
3200 * below means it will be recorded in a state block change, but it
3201 * works regardless where it is recorded.
3202 * If this is found to be wrong, change to StateBlock.
3204 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3205 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
3207 if (State <= HIGHEST_TRANSFORMSTATE)
3209 mat = &This->updateStateBlock->transforms[State];
3211 FIXME("Unhandled transform state!!\n");
3214 multiply_matrix(&temp, mat, pMatrix);
3216 /* Apply change via set transform - will reapply to eg. lights this way */
3217 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
3223 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
3224 you can reference any indexes you want as long as that number max are enabled at any
3225 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
3226 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
3227 but when recording, just build a chain pretty much of commands to be replayed. */
3229 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
3231 PLIGHTINFOEL *object = NULL;
3232 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3235 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3236 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
3238 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
3242 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
3243 return WINED3DERR_INVALIDCALL;
3246 switch(pLight->Type) {
3247 case WINED3DLIGHT_POINT:
3248 case WINED3DLIGHT_SPOT:
3249 case WINED3DLIGHT_PARALLELPOINT:
3250 case WINED3DLIGHT_GLSPOT:
3251 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
3254 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
3255 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
3256 return WINED3DERR_INVALIDCALL;
3260 case WINED3DLIGHT_DIRECTIONAL:
3261 /* Ignores attenuation */
3265 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
3266 return WINED3DERR_INVALIDCALL;
3269 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3270 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3271 if(object->OriginalIndex == Index) break;
3276 TRACE("Adding new light\n");
3277 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
3279 ERR("Out of memory error when allocating a light\n");
3280 return E_OUTOFMEMORY;
3282 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
3283 object->glIndex = -1;
3284 object->OriginalIndex = Index;
3285 object->changed = TRUE;
3288 /* Initialize the object */
3289 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,
3290 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
3291 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
3292 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
3293 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
3294 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
3295 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
3297 /* Save away the information */
3298 object->OriginalParms = *pLight;
3300 switch (pLight->Type) {
3301 case WINED3DLIGHT_POINT:
3303 object->lightPosn[0] = pLight->Position.x;
3304 object->lightPosn[1] = pLight->Position.y;
3305 object->lightPosn[2] = pLight->Position.z;
3306 object->lightPosn[3] = 1.0f;
3307 object->cutoff = 180.0f;
3311 case WINED3DLIGHT_DIRECTIONAL:
3313 object->lightPosn[0] = -pLight->Direction.x;
3314 object->lightPosn[1] = -pLight->Direction.y;
3315 object->lightPosn[2] = -pLight->Direction.z;
3316 object->lightPosn[3] = 0.0;
3317 object->exponent = 0.0f;
3318 object->cutoff = 180.0f;
3321 case WINED3DLIGHT_SPOT:
3323 object->lightPosn[0] = pLight->Position.x;
3324 object->lightPosn[1] = pLight->Position.y;
3325 object->lightPosn[2] = pLight->Position.z;
3326 object->lightPosn[3] = 1.0;
3329 object->lightDirn[0] = pLight->Direction.x;
3330 object->lightDirn[1] = pLight->Direction.y;
3331 object->lightDirn[2] = pLight->Direction.z;
3332 object->lightDirn[3] = 1.0;
3335 * opengl-ish and d3d-ish spot lights use too different models for the
3336 * light "intensity" as a function of the angle towards the main light direction,
3337 * so we only can approximate very roughly.
3338 * however spot lights are rather rarely used in games (if ever used at all).
3339 * furthermore if still used, probably nobody pays attention to such details.
3341 if (pLight->Falloff == 0) {
3342 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
3343 * falloff resp. exponent parameter as an exponent, so the spot light lighting
3344 * will always be 1.0 for both of them, and we don't have to care for the
3345 * rest of the rather complex calculation
3347 object->exponent = 0;
3349 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
3350 if (rho < 0.0001) rho = 0.0001f;
3351 object->exponent = -0.3/log(cos(rho/2));
3353 if (object->exponent > 128.0) {
3354 object->exponent = 128.0;
3356 object->cutoff = pLight->Phi*90/M_PI;
3362 FIXME("Unrecognized light type %d\n", pLight->Type);
3365 /* Update the live definitions if the light is currently assigned a glIndex */
3366 if (object->glIndex != -1 && !This->isRecordingState) {
3367 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
3372 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
3373 PLIGHTINFOEL *lightInfo = NULL;
3374 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3375 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
3377 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
3379 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3380 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3381 if(lightInfo->OriginalIndex == Index) break;
3385 if (lightInfo == NULL) {
3386 TRACE("Light information requested but light not defined\n");
3387 return WINED3DERR_INVALIDCALL;
3390 *pLight = lightInfo->OriginalParms;
3395 * Get / Set Light Enable
3396 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
3398 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
3399 PLIGHTINFOEL *lightInfo = NULL;
3400 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3401 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3403 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
3405 /* Tests show true = 128...not clear why */
3406 Enable = Enable? 128: 0;
3408 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3409 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3410 if(lightInfo->OriginalIndex == Index) break;
3413 TRACE("Found light: %p\n", lightInfo);
3415 /* Special case - enabling an undefined light creates one with a strict set of parms! */
3416 if (lightInfo == NULL) {
3418 TRACE("Light enabled requested but light not defined, so defining one!\n");
3419 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
3421 /* Search for it again! Should be fairly quick as near head of list */
3422 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3423 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3424 if(lightInfo->OriginalIndex == Index) break;
3427 if (lightInfo == NULL) {
3428 FIXME("Adding default lights has failed dismally\n");
3429 return WINED3DERR_INVALIDCALL;
3433 lightInfo->enabledChanged = TRUE;
3435 if(lightInfo->glIndex != -1) {
3436 if(!This->isRecordingState) {
3437 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
3440 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
3441 lightInfo->glIndex = -1;
3443 TRACE("Light already disabled, nothing to do\n");
3445 lightInfo->enabled = FALSE;
3447 lightInfo->enabled = TRUE;
3448 if (lightInfo->glIndex != -1) {
3450 TRACE("Nothing to do as light was enabled\n");
3453 /* Find a free gl light */
3454 for(i = 0; i < This->maxConcurrentLights; i++) {
3455 if(This->updateStateBlock->activeLights[i] == NULL) {
3456 This->updateStateBlock->activeLights[i] = lightInfo;
3457 lightInfo->glIndex = i;
3461 if(lightInfo->glIndex == -1) {
3462 /* Our tests show that Windows returns D3D_OK in this situation, even with
3463 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3464 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3465 * as well for those lights.
3467 * TODO: Test how this affects rendering
3469 WARN("Too many concurrently active lights\n");
3473 /* i == lightInfo->glIndex */
3474 if(!This->isRecordingState) {
3475 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3483 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3485 PLIGHTINFOEL *lightInfo = NULL;
3486 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3488 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3489 TRACE("(%p) : for idx(%d)\n", This, Index);
3491 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3492 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3493 if(lightInfo->OriginalIndex == Index) break;
3497 if (lightInfo == NULL) {
3498 TRACE("Light enabled state requested but light not defined\n");
3499 return WINED3DERR_INVALIDCALL;
3501 /* true is 128 according to SetLightEnable */
3502 *pEnable = lightInfo->enabled ? 128 : 0;
3507 * Get / Set Clip Planes
3509 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3510 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3511 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3513 /* Validate Index */
3514 if (Index >= GL_LIMITS(clipplanes)) {
3515 TRACE("Application has requested clipplane this device doesn't support\n");
3516 return WINED3DERR_INVALIDCALL;
3519 This->updateStateBlock->changed.clipplane |= 1 << Index;
3521 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3522 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3523 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3524 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3525 TRACE("Application is setting old values over, nothing to do\n");
3529 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3530 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3531 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3532 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3534 /* Handle recording of state blocks */
3535 if (This->isRecordingState) {
3536 TRACE("Recording... not performing anything\n");
3540 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3545 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3546 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3547 TRACE("(%p) : for idx %d\n", This, Index);
3549 /* Validate Index */
3550 if (Index >= GL_LIMITS(clipplanes)) {
3551 TRACE("Application has requested clipplane this device doesn't support\n");
3552 return WINED3DERR_INVALIDCALL;
3555 pPlane[0] = This->stateBlock->clipplane[Index][0];
3556 pPlane[1] = This->stateBlock->clipplane[Index][1];
3557 pPlane[2] = This->stateBlock->clipplane[Index][2];
3558 pPlane[3] = This->stateBlock->clipplane[Index][3];
3563 * Get / Set Clip Plane Status
3564 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3566 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3567 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3568 FIXME("(%p) : stub\n", This);
3569 if (NULL == pClipStatus) {
3570 return WINED3DERR_INVALIDCALL;
3572 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3573 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3577 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3578 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3579 FIXME("(%p) : stub\n", This);
3580 if (NULL == pClipStatus) {
3581 return WINED3DERR_INVALIDCALL;
3583 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3584 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3589 * Get / Set Material
3591 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3592 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3594 This->updateStateBlock->changed.material = TRUE;
3595 This->updateStateBlock->material = *pMaterial;
3597 /* Handle recording of state blocks */
3598 if (This->isRecordingState) {
3599 TRACE("Recording... not performing anything\n");
3603 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3607 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3608 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3609 *pMaterial = This->updateStateBlock->material;
3610 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3611 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3612 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3613 pMaterial->Ambient.b, pMaterial->Ambient.a);
3614 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3615 pMaterial->Specular.b, pMaterial->Specular.a);
3616 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3617 pMaterial->Emissive.b, pMaterial->Emissive.a);
3618 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3626 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DBuffer* pIndexData, WINED3DFORMAT fmt) {
3627 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3628 IWineD3DBuffer *oldIdxs;
3630 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3631 oldIdxs = This->updateStateBlock->pIndexData;
3633 This->updateStateBlock->changed.indices = TRUE;
3634 This->updateStateBlock->pIndexData = pIndexData;
3635 This->updateStateBlock->IndexFmt = fmt;
3637 /* Handle recording of state blocks */
3638 if (This->isRecordingState) {
3639 TRACE("Recording... not performing anything\n");
3640 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
3641 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
3645 if(oldIdxs != pIndexData) {
3646 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3648 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
3649 IWineD3DBuffer_AddRef(pIndexData);
3652 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
3653 IWineD3DBuffer_Release(oldIdxs);
3660 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DBuffer** ppIndexData) {
3661 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3663 *ppIndexData = This->stateBlock->pIndexData;
3665 /* up ref count on ppindexdata */
3667 IWineD3DBuffer_AddRef(*ppIndexData);
3668 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3670 TRACE("(%p) No index data set\n", This);
3672 TRACE("Returning %p\n", *ppIndexData);
3677 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3678 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3679 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3680 TRACE("(%p)->(%d)\n", This, BaseIndex);
3682 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3683 TRACE("Application is setting the old value over, nothing to do\n");
3687 This->updateStateBlock->baseVertexIndex = BaseIndex;
3689 if (This->isRecordingState) {
3690 TRACE("Recording... not performing anything\n");
3693 /* The base vertex index affects the stream sources */
3694 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3698 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3699 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3700 TRACE("(%p) : base_index %p\n", This, base_index);
3702 *base_index = This->stateBlock->baseVertexIndex;
3704 TRACE("Returning %u\n", *base_index);
3710 * Get / Set Viewports
3712 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3713 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3715 TRACE("(%p)\n", This);
3716 This->updateStateBlock->changed.viewport = TRUE;
3717 This->updateStateBlock->viewport = *pViewport;
3719 /* Handle recording of state blocks */
3720 if (This->isRecordingState) {
3721 TRACE("Recording... not performing anything\n");
3725 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3726 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3728 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3733 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3734 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3735 TRACE("(%p)\n", This);
3736 *pViewport = This->stateBlock->viewport;
3741 * Get / Set Render States
3742 * TODO: Verify against dx9 definitions
3744 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3746 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3747 DWORD oldValue = This->stateBlock->renderState[State];
3749 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3751 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3752 This->updateStateBlock->renderState[State] = Value;
3754 /* Handle recording of state blocks */
3755 if (This->isRecordingState) {
3756 TRACE("Recording... not performing anything\n");
3760 /* Compared here and not before the assignment to allow proper stateblock recording */
3761 if(Value == oldValue) {
3762 TRACE("Application is setting the old value over, nothing to do\n");
3764 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3770 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3771 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3772 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3773 *pValue = This->stateBlock->renderState[State];
3778 * Get / Set Sampler States
3779 * TODO: Verify against dx9 definitions
3782 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3783 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3786 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3787 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3789 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3790 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3793 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3794 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3795 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3798 * SetSampler is designed to allow for more than the standard up to 8 textures
3799 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3800 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3802 * http://developer.nvidia.com/object/General_FAQ.html#t6
3804 * There are two new settings for GForce
3806 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3807 * and the texture one:
3808 * GL_MAX_TEXTURE_COORDS_ARB.
3809 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3812 oldValue = This->stateBlock->samplerState[Sampler][Type];
3813 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3814 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3816 /* Handle recording of state blocks */
3817 if (This->isRecordingState) {
3818 TRACE("Recording... not performing anything\n");
3822 if(oldValue == Value) {
3823 TRACE("Application is setting the old value over, nothing to do\n");
3827 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3832 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3833 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3835 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3836 This, Sampler, debug_d3dsamplerstate(Type), Type);
3838 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3839 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3842 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3843 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3844 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3846 *Value = This->stateBlock->samplerState[Sampler][Type];
3847 TRACE("(%p) : Returning %#x\n", This, *Value);
3852 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3853 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3855 This->updateStateBlock->changed.scissorRect = TRUE;
3856 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3857 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3860 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3862 if(This->isRecordingState) {
3863 TRACE("Recording... not performing anything\n");
3867 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3872 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3873 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3875 *pRect = This->updateStateBlock->scissorRect;
3876 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3880 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3882 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3884 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3886 This->updateStateBlock->vertexDecl = pDecl;
3887 This->updateStateBlock->changed.vertexDecl = TRUE;
3889 if (This->isRecordingState) {
3890 TRACE("Recording... not performing anything\n");
3892 } else if(pDecl == oldDecl) {
3893 /* Checked after the assignment to allow proper stateblock recording */
3894 TRACE("Application is setting the old declaration over, nothing to do\n");
3898 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3902 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3903 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3905 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3907 *ppDecl = This->stateBlock->vertexDecl;
3908 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3912 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3913 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3914 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3916 This->updateStateBlock->vertexShader = pShader;
3917 This->updateStateBlock->changed.vertexShader = TRUE;
3919 if (This->isRecordingState) {
3920 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3921 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3922 TRACE("Recording... not performing anything\n");
3924 } else if(oldShader == pShader) {
3925 /* Checked here to allow proper stateblock recording */
3926 TRACE("App is setting the old shader over, nothing to do\n");
3930 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3931 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3932 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3934 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3939 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3940 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3942 if (NULL == ppShader) {
3943 return WINED3DERR_INVALIDCALL;
3945 *ppShader = This->stateBlock->vertexShader;
3946 if( NULL != *ppShader)
3947 IWineD3DVertexShader_AddRef(*ppShader);
3949 TRACE("(%p) : returning %p\n", This, *ppShader);
3953 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3954 IWineD3DDevice *iface,
3956 CONST BOOL *srcData,
3959 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3960 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3962 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3963 iface, srcData, start, count);
3965 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3967 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3968 for (i = 0; i < cnt; i++)
3969 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3971 for (i = start; i < cnt + start; ++i) {
3972 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3975 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3980 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3981 IWineD3DDevice *iface,
3986 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3987 int cnt = min(count, MAX_CONST_B - start);
3989 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3990 iface, dstData, start, count);
3992 if (dstData == NULL || cnt < 0)
3993 return WINED3DERR_INVALIDCALL;
3995 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3999 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
4000 IWineD3DDevice *iface,
4005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4006 unsigned int i, cnt = min(count, MAX_CONST_I - start);
4008 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4009 iface, srcData, start, count);
4011 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
4013 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4014 for (i = 0; i < cnt; i++)
4015 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4016 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4018 for (i = start; i < cnt + start; ++i) {
4019 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
4022 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
4027 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
4028 IWineD3DDevice *iface,
4033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4034 int cnt = min(count, MAX_CONST_I - start);
4036 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4037 iface, dstData, start, count);
4039 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
4040 return WINED3DERR_INVALIDCALL;
4042 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4046 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
4047 IWineD3DDevice *iface,
4049 CONST float *srcData,
4052 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4055 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4056 iface, srcData, start, count);
4058 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4059 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
4060 return WINED3DERR_INVALIDCALL;
4062 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4064 for (i = 0; i < count; i++)
4065 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4066 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4069 if (!This->isRecordingState)
4071 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
4072 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
4075 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
4076 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
4081 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
4082 IWineD3DDevice *iface,
4087 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4088 int cnt = min(count, This->d3d_vshader_constantF - start);
4090 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4091 iface, dstData, start, count);
4093 if (dstData == NULL || cnt < 0)
4094 return WINED3DERR_INVALIDCALL;
4096 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4100 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
4102 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
4104 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
4108 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
4109 int i = This->rev_tex_unit_map[unit];
4110 int j = This->texUnitMap[stage];
4112 This->texUnitMap[stage] = unit;
4113 if (i != -1 && i != stage) {
4114 This->texUnitMap[i] = -1;
4117 This->rev_tex_unit_map[unit] = stage;
4118 if (j != -1 && j != unit) {
4119 This->rev_tex_unit_map[j] = -1;
4123 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
4126 This->fixed_function_usage_map = 0;
4127 for (i = 0; i < MAX_TEXTURES; ++i) {
4128 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
4129 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
4130 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
4131 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
4132 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
4133 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
4134 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
4135 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
4137 if (color_op == WINED3DTOP_DISABLE) {
4138 /* Not used, and disable higher stages */
4142 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
4143 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
4144 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
4145 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
4146 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
4147 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
4148 This->fixed_function_usage_map |= (1 << i);
4151 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
4152 This->fixed_function_usage_map |= (1 << (i + 1));
4157 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
4158 unsigned int i, tex;
4161 device_update_fixed_function_usage_map(This);
4162 ffu_map = This->fixed_function_usage_map;
4164 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
4165 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
4166 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
4168 if (!(ffu_map & 1)) continue;
4170 if (This->texUnitMap[i] != i) {
4171 device_map_stage(This, i, i);
4172 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
4173 markTextureStagesDirty(This, i);
4179 /* Now work out the mapping */
4181 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
4183 if (!(ffu_map & 1)) continue;
4185 if (This->texUnitMap[i] != tex) {
4186 device_map_stage(This, i, tex);
4187 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
4188 markTextureStagesDirty(This, i);
4195 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
4196 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
4197 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
4200 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
4201 if (sampler_type[i] && This->texUnitMap[i] != i)
4203 device_map_stage(This, i, i);
4204 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
4205 if (i < MAX_TEXTURES) {
4206 markTextureStagesDirty(This, i);
4212 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
4213 const DWORD *vshader_sampler_tokens, int unit)
4215 int current_mapping = This->rev_tex_unit_map[unit];
4217 if (current_mapping == -1) {
4218 /* Not currently used */
4222 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
4223 /* Used by a fragment sampler */
4225 if (!pshader_sampler_tokens) {
4226 /* No pixel shader, check fixed function */
4227 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
4230 /* Pixel shader, check the shader's sampler map */
4231 return !pshader_sampler_tokens[current_mapping];
4234 /* Used by a vertex sampler */
4235 return !vshader_sampler_tokens[current_mapping];
4238 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
4239 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
4240 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
4241 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
4242 int start = GL_LIMITS(combined_samplers) - 1;
4246 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
4248 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
4249 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
4250 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
4253 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
4254 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
4255 if (vshader_sampler_type[i])
4257 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
4259 /* Already mapped somewhere */
4263 while (start >= 0) {
4264 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
4266 device_map_stage(This, vsampler_idx, start);
4267 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
4279 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
4280 BOOL vs = use_vs(This->stateBlock);
4281 BOOL ps = use_ps(This->stateBlock);
4284 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
4285 * that would be really messy and require shader recompilation
4286 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
4287 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
4290 device_map_psamplers(This);
4292 device_map_fixed_function_samplers(This);
4296 device_map_vsamplers(This, ps);
4300 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4301 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4302 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4303 This->updateStateBlock->pixelShader = pShader;
4304 This->updateStateBlock->changed.pixelShader = TRUE;
4306 /* Handle recording of state blocks */
4307 if (This->isRecordingState) {
4308 TRACE("Recording... not performing anything\n");
4311 if (This->isRecordingState) {
4312 TRACE("Recording... not performing anything\n");
4313 if(pShader) IWineD3DPixelShader_AddRef(pShader);
4314 if(oldShader) IWineD3DPixelShader_Release(oldShader);
4318 if(pShader == oldShader) {
4319 TRACE("App is setting the old pixel shader over, nothing to do\n");
4323 if(pShader) IWineD3DPixelShader_AddRef(pShader);
4324 if(oldShader) IWineD3DPixelShader_Release(oldShader);
4326 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4327 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4332 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4333 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4335 if (NULL == ppShader) {
4336 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4337 return WINED3DERR_INVALIDCALL;
4340 *ppShader = This->stateBlock->pixelShader;
4341 if (NULL != *ppShader) {
4342 IWineD3DPixelShader_AddRef(*ppShader);
4344 TRACE("(%p) : returning %p\n", This, *ppShader);
4348 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4349 IWineD3DDevice *iface,
4351 CONST BOOL *srcData,
4354 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4355 unsigned int i, cnt = min(count, MAX_CONST_B - start);
4357 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
4358 iface, srcData, start, count);
4360 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
4362 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4363 for (i = 0; i < cnt; i++)
4364 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4366 for (i = start; i < cnt + start; ++i) {
4367 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
4370 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4375 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4376 IWineD3DDevice *iface,
4381 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4382 int cnt = min(count, MAX_CONST_B - start);
4384 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4385 iface, dstData, start, count);
4387 if (dstData == NULL || cnt < 0)
4388 return WINED3DERR_INVALIDCALL;
4390 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4394 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4395 IWineD3DDevice *iface,
4400 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4401 unsigned int i, cnt = min(count, MAX_CONST_I - start);
4403 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
4404 iface, srcData, start, count);
4406 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
4408 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4409 for (i = 0; i < cnt; i++)
4410 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4411 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4413 for (i = start; i < cnt + start; ++i) {
4414 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
4417 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4422 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4423 IWineD3DDevice *iface,
4428 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4429 int cnt = min(count, MAX_CONST_I - start);
4431 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4432 iface, dstData, start, count);
4434 if (dstData == NULL || cnt < 0)
4435 return WINED3DERR_INVALIDCALL;
4437 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4441 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4442 IWineD3DDevice *iface,
4444 CONST float *srcData,
4447 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4450 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4451 iface, srcData, start, count);
4453 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4454 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
4455 return WINED3DERR_INVALIDCALL;
4457 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4459 for (i = 0; i < count; i++)
4460 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4461 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4464 if (!This->isRecordingState)
4466 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
4467 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4470 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
4471 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
4476 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4477 IWineD3DDevice *iface,
4482 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4483 int cnt = min(count, This->d3d_pshader_constantF - start);
4485 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4486 iface, dstData, start, count);
4488 if (dstData == NULL || cnt < 0)
4489 return WINED3DERR_INVALIDCALL;
4491 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4495 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4496 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4497 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
4500 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4503 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4507 if (stream_info->elements[WINED3D_FFP_NORMAL].data)
4509 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4512 if (!stream_info->elements[WINED3D_FFP_POSITION].data)
4514 ERR("Source has no position mask\n");
4515 return WINED3DERR_INVALIDCALL;
4518 /* We might access VBOs from this code, so hold the lock */
4521 if (dest->resource.allocatedMemory == NULL) {
4522 buffer_get_sysmem(dest);
4525 /* Get a pointer into the destination vbo(create one if none exists) and
4526 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4528 if (!dest->buffer_object && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT))
4530 dest->flags |= WINED3D_BUFFER_CREATEBO;
4531 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
4534 if (dest->buffer_object)
4536 unsigned char extrabytes = 0;
4537 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4538 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4539 * this may write 4 extra bytes beyond the area that should be written
4541 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4542 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4543 if(!dest_conv_addr) {
4544 ERR("Out of memory\n");
4545 /* Continue without storing converted vertices */
4547 dest_conv = dest_conv_addr;
4551 * a) WINED3DRS_CLIPPING is enabled
4552 * b) WINED3DVOP_CLIP is passed
4554 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4555 static BOOL warned = FALSE;
4557 * The clipping code is not quite correct. Some things need
4558 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4559 * so disable clipping for now.
4560 * (The graphics in Half-Life are broken, and my processvertices
4561 * test crashes with IDirect3DDevice3)
4567 FIXME("Clipping is broken and disabled for now\n");
4569 } else doClip = FALSE;
4570 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4572 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4575 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4576 WINED3DTS_PROJECTION,
4578 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4579 WINED3DTS_WORLDMATRIX(0),
4582 TRACE("View mat:\n");
4583 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);
4584 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);
4585 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);
4586 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);
4588 TRACE("Proj mat:\n");
4589 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);
4590 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);
4591 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);
4592 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);
4594 TRACE("World mat:\n");
4595 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);
4596 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);
4597 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);
4598 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);
4600 /* Get the viewport */
4601 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4602 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4603 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4605 multiply_matrix(&mat,&view_mat,&world_mat);
4606 multiply_matrix(&mat,&proj_mat,&mat);
4608 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4610 for (i = 0; i < dwCount; i+= 1) {
4611 unsigned int tex_index;
4613 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4614 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4615 /* The position first */
4616 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
4617 const float *p = (const float *)(element->data + i * element->stride);
4619 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4621 /* Multiplication with world, view and projection matrix */
4622 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);
4623 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);
4624 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);
4625 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);
4627 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4629 /* WARNING: The following things are taken from d3d7 and were not yet checked
4630 * against d3d8 or d3d9!
4633 /* Clipping conditions: From msdn
4635 * A vertex is clipped if it does not match the following requirements
4639 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4641 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4642 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4647 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4648 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4651 /* "Normal" viewport transformation (not clipped)
4652 * 1) The values are divided by rhw
4653 * 2) The y axis is negative, so multiply it with -1
4654 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4655 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4656 * 4) Multiply x with Width/2 and add Width/2
4657 * 5) The same for the height
4658 * 6) Add the viewpoint X and Y to the 2D coordinates and
4659 * The minimum Z value to z
4660 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4662 * Well, basically it's simply a linear transformation into viewport
4674 z *= vp.MaxZ - vp.MinZ;
4676 x += vp.Width / 2 + vp.X;
4677 y += vp.Height / 2 + vp.Y;
4682 /* That vertex got clipped
4683 * Contrary to OpenGL it is not dropped completely, it just
4684 * undergoes a different calculation.
4686 TRACE("Vertex got clipped\n");
4693 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4694 * outside of the main vertex buffer memory. That needs some more
4699 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4702 ( (float *) dest_ptr)[0] = x;
4703 ( (float *) dest_ptr)[1] = y;
4704 ( (float *) dest_ptr)[2] = z;
4705 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4707 dest_ptr += 3 * sizeof(float);
4709 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4710 dest_ptr += sizeof(float);
4715 ( (float *) dest_conv)[0] = x * w;
4716 ( (float *) dest_conv)[1] = y * w;
4717 ( (float *) dest_conv)[2] = z * w;
4718 ( (float *) dest_conv)[3] = w;
4720 dest_conv += 3 * sizeof(float);
4722 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4723 dest_conv += sizeof(float);
4727 if (DestFVF & WINED3DFVF_PSIZE) {
4728 dest_ptr += sizeof(DWORD);
4729 if(dest_conv) dest_conv += sizeof(DWORD);
4731 if (DestFVF & WINED3DFVF_NORMAL) {
4732 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4733 const float *normal = (const float *)(element->data + i * element->stride);
4734 /* AFAIK this should go into the lighting information */
4735 FIXME("Didn't expect the destination to have a normal\n");
4736 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4738 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4742 if (DestFVF & WINED3DFVF_DIFFUSE) {
4743 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4744 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4746 static BOOL warned = FALSE;
4749 ERR("No diffuse color in source, but destination has one\n");
4753 *( (DWORD *) dest_ptr) = 0xffffffff;
4754 dest_ptr += sizeof(DWORD);
4757 *( (DWORD *) dest_conv) = 0xffffffff;
4758 dest_conv += sizeof(DWORD);
4762 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4764 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4765 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4766 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4767 dest_conv += sizeof(DWORD);
4772 if (DestFVF & WINED3DFVF_SPECULAR) {
4773 /* What's the color value in the feedback buffer? */
4774 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4775 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4777 static BOOL warned = FALSE;
4780 ERR("No specular color in source, but destination has one\n");
4784 *( (DWORD *) dest_ptr) = 0xFF000000;
4785 dest_ptr += sizeof(DWORD);
4788 *( (DWORD *) dest_conv) = 0xFF000000;
4789 dest_conv += sizeof(DWORD);
4793 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4795 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4796 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4797 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4798 dest_conv += sizeof(DWORD);
4803 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4804 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4805 const float *tex_coord = (const float *)(element->data + i * element->stride);
4807 ERR("No source texture, but destination requests one\n");
4808 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4809 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4812 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4814 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4821 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4822 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4823 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4824 dwCount * get_flexible_vertex_size(DestFVF),
4826 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4827 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4834 #undef copy_and_next
4836 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4837 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4840 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4841 struct wined3d_stream_info stream_info;
4842 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4843 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4846 ERR("Output vertex declaration not implemented yet\n");
4849 /* Need any context to write to the vbo. */
4850 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4852 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4853 * control the streamIsUP flag, thus restore it afterwards.
4855 This->stateBlock->streamIsUP = FALSE;
4856 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4857 This->stateBlock->streamIsUP = streamWasUP;
4859 if(vbo || SrcStartIndex) {
4861 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4862 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4864 * Also get the start index in, but only loop over all elements if there's something to add at all.
4866 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4868 struct wined3d_stream_info_element *e = &stream_info.elements[i];
4869 if (e->buffer_object)
4871 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
4872 e->buffer_object = 0;
4873 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
4875 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4876 vb->buffer_object = 0;
4879 if (e->data) e->data += e->stride * SrcStartIndex;
4883 return process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4884 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4888 * Get / Set Texture Stage States
4889 * TODO: Verify against dx9 definitions
4891 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4893 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4895 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4897 if (Stage >= MAX_TEXTURES) {
4898 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4902 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4903 This->updateStateBlock->textureState[Stage][Type] = Value;
4905 if (This->isRecordingState) {
4906 TRACE("Recording... not performing anything\n");
4910 /* Checked after the assignments to allow proper stateblock recording */
4911 if(oldValue == Value) {
4912 TRACE("App is setting the old value over, nothing to do\n");
4916 if(Stage > This->stateBlock->lowest_disabled_stage &&
4917 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4918 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4919 * Changes in other states are important on disabled stages too
4924 if(Type == WINED3DTSS_COLOROP) {
4927 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4928 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4929 * they have to be disabled
4931 * The current stage is dirtified below.
4933 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4934 TRACE("Additionally dirtifying stage %u\n", i);
4935 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4937 This->stateBlock->lowest_disabled_stage = Stage;
4938 TRACE("New lowest disabled: %u\n", Stage);
4939 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4940 /* Previously disabled stage enabled. Stages above it may need enabling
4941 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4942 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4944 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4947 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4948 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4951 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4952 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4954 This->stateBlock->lowest_disabled_stage = i;
4955 TRACE("New lowest disabled: %u\n", i);
4959 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4964 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4965 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4966 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4967 *pValue = This->updateStateBlock->textureState[Stage][Type];
4974 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4975 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4976 IWineD3DBaseTexture *oldTexture;
4978 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4980 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4981 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4984 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4985 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4986 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4989 oldTexture = This->updateStateBlock->textures[Stage];
4991 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4992 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
4994 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4995 return WINED3DERR_INVALIDCALL;
4998 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4999 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
5001 This->updateStateBlock->changed.textures |= 1 << Stage;
5002 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
5003 This->updateStateBlock->textures[Stage] = pTexture;
5005 /* Handle recording of state blocks */
5006 if (This->isRecordingState) {
5007 TRACE("Recording... not performing anything\n");
5011 if(oldTexture == pTexture) {
5012 TRACE("App is setting the same texture again, nothing to do\n");
5016 /** NOTE: MSDN says that setTexture increases the reference count,
5017 * and that the application must set the texture back to null (or have a leaky application),
5018 * This means we should pass the refcount up to the parent
5019 *******************************/
5020 if (NULL != This->updateStateBlock->textures[Stage]) {
5021 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
5022 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
5023 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
5025 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
5027 if (!oldTexture || dimensions != IWineD3DBaseTexture_GetTextureDimensions(oldTexture))
5029 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
5032 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
5033 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
5034 * so the COLOROP and ALPHAOP have to be dirtified.
5036 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
5037 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
5039 if(bindCount == 1) {
5040 new->baseTexture.sampler = Stage;
5042 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
5046 if (NULL != oldTexture) {
5047 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
5048 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
5050 IWineD3DBaseTexture_Release(oldTexture);
5051 if(pTexture == NULL && Stage < MAX_TEXTURES) {
5052 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
5053 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
5056 if(bindCount && old->baseTexture.sampler == Stage) {
5058 /* Have to do a search for the other sampler(s) where the texture is bound to
5059 * Shouldn't happen as long as apps bind a texture only to one stage
5061 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
5062 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5063 if(This->updateStateBlock->textures[i] == oldTexture) {
5064 old->baseTexture.sampler = i;
5071 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
5076 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
5077 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5079 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
5081 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
5082 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
5085 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
5086 ERR("Current stage overflows textures array (stage %d)\n", Stage);
5087 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
5090 *ppTexture=This->stateBlock->textures[Stage];
5092 IWineD3DBaseTexture_AddRef(*ppTexture);
5094 TRACE("(%p) : Returning %p\n", This, *ppTexture);
5102 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
5103 IWineD3DSurface **ppBackBuffer) {
5104 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5105 IWineD3DSwapChain *swapChain;
5108 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
5110 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5111 if (hr == WINED3D_OK) {
5112 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
5113 IWineD3DSwapChain_Release(swapChain);
5115 *ppBackBuffer = NULL;
5120 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
5121 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5122 WARN("(%p) : stub, calling idirect3d for now\n", This);
5123 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
5126 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
5127 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5128 IWineD3DSwapChain *swapChain;
5131 if(iSwapChain > 0) {
5132 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5133 if (hr == WINED3D_OK) {
5134 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
5135 IWineD3DSwapChain_Release(swapChain);
5137 FIXME("(%p) Error getting display mode\n", This);
5140 /* Don't read the real display mode,
5141 but return the stored mode instead. X11 can't change the color
5142 depth, and some apps are pretty angry if they SetDisplayMode from
5143 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
5145 Also don't relay to the swapchain because with ddraw it's possible
5146 that there isn't a swapchain at all */
5147 pMode->Width = This->ddraw_width;
5148 pMode->Height = This->ddraw_height;
5149 pMode->Format = This->ddraw_format;
5150 pMode->RefreshRate = 0;
5158 * Stateblock related functions
5161 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
5162 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5163 IWineD3DStateBlock *stateblock;
5166 TRACE("(%p)\n", This);
5168 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
5170 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
5171 if (FAILED(hr)) return hr;
5173 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
5174 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
5175 This->isRecordingState = TRUE;
5177 TRACE("(%p) recording stateblock %p\n", This, stateblock);
5182 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
5183 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5185 IWineD3DStateBlockImpl *object = This->updateStateBlock;
5187 if (!This->isRecordingState) {
5188 WARN("(%p) not recording! returning error\n", This);
5189 *ppStateBlock = NULL;
5190 return WINED3DERR_INVALIDCALL;
5193 for (i = 0; i <= WINEHIGHEST_RENDER_STATE >> 5; ++i)
5195 DWORD map = object->changed.renderState[i];
5196 for (j = 0; map; map >>= 1, ++j)
5198 if (!(map & 1)) continue;
5200 object->contained_render_states[object->num_contained_render_states++] = (i << 5) | j;
5204 for (i = 0; i <= HIGHEST_TRANSFORMSTATE >> 5; ++i)
5206 DWORD map = object->changed.transform[i];
5207 for (j = 0; map; map >>= 1, ++j)
5209 if (!(map & 1)) continue;
5211 object->contained_transform_states[object->num_contained_transform_states++] = (i << 5) | j;
5214 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
5215 if(object->changed.vertexShaderConstantsF[i]) {
5216 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
5217 object->num_contained_vs_consts_f++;
5220 for(i = 0; i < MAX_CONST_I; i++) {
5221 if (object->changed.vertexShaderConstantsI & (1 << i))
5223 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
5224 object->num_contained_vs_consts_i++;
5227 for(i = 0; i < MAX_CONST_B; i++) {
5228 if (object->changed.vertexShaderConstantsB & (1 << i))
5230 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
5231 object->num_contained_vs_consts_b++;
5234 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
5236 if (object->changed.pixelShaderConstantsF[i])
5238 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
5239 ++object->num_contained_ps_consts_f;
5242 for(i = 0; i < MAX_CONST_I; i++) {
5243 if (object->changed.pixelShaderConstantsI & (1 << i))
5245 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
5246 object->num_contained_ps_consts_i++;
5249 for(i = 0; i < MAX_CONST_B; i++) {
5250 if (object->changed.pixelShaderConstantsB & (1 << i))
5252 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
5253 object->num_contained_ps_consts_b++;
5256 for(i = 0; i < MAX_TEXTURES; i++) {
5257 DWORD map = object->changed.textureState[i];
5259 for(j = 0; map; map >>= 1, ++j)
5261 if (!(map & 1)) continue;
5263 object->contained_tss_states[object->num_contained_tss_states].stage = i;
5264 object->contained_tss_states[object->num_contained_tss_states].state = j;
5265 ++object->num_contained_tss_states;
5268 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
5269 DWORD map = object->changed.samplerState[i];
5271 for (j = 0; map; map >>= 1, ++j)
5273 if (!(map & 1)) continue;
5275 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
5276 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
5277 ++object->num_contained_sampler_states;
5281 *ppStateBlock = (IWineD3DStateBlock*) object;
5282 This->isRecordingState = FALSE;
5283 This->updateStateBlock = This->stateBlock;
5284 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5285 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5286 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5291 * Scene related functions
5293 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5294 /* At the moment we have no need for any functionality at the beginning
5296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5297 TRACE("(%p)\n", This);
5300 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
5301 return WINED3DERR_INVALIDCALL;
5303 This->inScene = TRUE;
5307 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5308 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5309 TRACE("(%p)\n", This);
5311 if(!This->inScene) {
5312 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
5313 return WINED3DERR_INVALIDCALL;
5316 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5317 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5319 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
5323 This->inScene = FALSE;
5327 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5328 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5329 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5330 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5331 IWineD3DSwapChain *swapChain = NULL;
5333 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5335 TRACE("(%p) Presenting the frame\n", This);
5337 for(i = 0 ; i < swapchains ; i ++) {
5339 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
5340 TRACE("presentinng chain %d, %p\n", i, swapChain);
5341 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5342 IWineD3DSwapChain_Release(swapChain);
5348 /* Not called from the VTable (internal subroutine) */
5349 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
5350 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
5351 float Z, DWORD Stencil) {
5352 GLbitfield glMask = 0;
5354 WINED3DRECT curRect;
5356 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
5357 UINT drawable_width, drawable_height;
5358 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
5359 IWineD3DSwapChainImpl *swapchain = NULL;
5361 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5362 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5363 * for the cleared parts, and the untouched parts.
5365 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5366 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5367 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5368 * checking all this if the dest surface is in the drawable anyway.
5370 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5372 if(vp->X != 0 || vp->Y != 0 ||
5373 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5374 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5377 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5378 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5379 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5380 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5381 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5384 if(Count > 0 && pRects && (
5385 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5386 pRects[0].x2 < target->currentDesc.Width ||
5387 pRects[0].y2 < target->currentDesc.Height)) {
5388 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5395 target->get_drawable_size(target, &drawable_width, &drawable_height);
5397 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5400 /* Only set the values up once, as they are not changing */
5401 if (Flags & WINED3DCLEAR_STENCIL) {
5402 glClearStencil(Stencil);
5403 checkGLcall("glClearStencil");
5404 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5405 glStencilMask(0xFFFFFFFF);
5408 if (Flags & WINED3DCLEAR_ZBUFFER) {
5409 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5410 glDepthMask(GL_TRUE);
5412 checkGLcall("glClearDepth");
5413 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5414 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5416 if (vp->X != 0 || vp->Y != 0 ||
5417 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5418 surface_load_ds_location(This->stencilBufferTarget, location);
5420 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5421 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5422 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5423 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5424 surface_load_ds_location(This->stencilBufferTarget, location);
5426 else if (Count > 0 && pRects && (
5427 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5428 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5429 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5430 surface_load_ds_location(This->stencilBufferTarget, location);
5434 if (Flags & WINED3DCLEAR_TARGET) {
5435 TRACE("Clearing screen with glClear to color %x\n", Color);
5436 glClearColor(D3DCOLOR_R(Color),
5440 checkGLcall("glClearColor");
5442 /* Clear ALL colors! */
5443 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5444 glMask = glMask | GL_COLOR_BUFFER_BIT;
5447 vp_rect.left = vp->X;
5448 vp_rect.top = vp->Y;
5449 vp_rect.right = vp->X + vp->Width;
5450 vp_rect.bottom = vp->Y + vp->Height;
5451 if (!(Count > 0 && pRects)) {
5452 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5453 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5455 if(This->render_offscreen) {
5456 glScissor(vp_rect.left, vp_rect.top,
5457 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5459 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5460 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5462 checkGLcall("glScissor");
5464 checkGLcall("glClear");
5466 /* Now process each rect in turn */
5467 for (i = 0; i < Count; i++) {
5468 /* Note gl uses lower left, width/height */
5469 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5470 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5471 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5473 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5474 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5475 curRect.x1, (target->currentDesc.Height - curRect.y2),
5476 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5478 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5479 * The rectangle is not cleared, no error is returned, but further rectanlges are
5480 * still cleared if they are valid
5482 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5483 TRACE("Rectangle with negative dimensions, ignoring\n");
5487 if(This->render_offscreen) {
5488 glScissor(curRect.x1, curRect.y1,
5489 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5491 glScissor(curRect.x1, drawable_height - curRect.y2,
5492 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5494 checkGLcall("glScissor");
5497 checkGLcall("glClear");
5501 /* Restore the old values (why..?) */
5502 if (Flags & WINED3DCLEAR_STENCIL) {
5503 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5505 if (Flags & WINED3DCLEAR_TARGET) {
5506 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5507 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5508 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5509 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5510 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5512 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5513 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5515 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5517 if (Flags & WINED3DCLEAR_ZBUFFER) {
5518 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5519 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5520 surface_modify_ds_location(This->stencilBufferTarget, location);
5525 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5526 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5529 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5535 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5536 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5537 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5538 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5540 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5541 Count, pRects, Flags, Color, Z, Stencil);
5543 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5544 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5545 /* TODO: What about depth stencil buffers without stencil bits? */
5546 return WINED3DERR_INVALIDCALL;
5549 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5556 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
5557 WINED3DPRIMITIVETYPE primitive_type)
5559 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5561 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
5563 This->updateStateBlock->changed.primitive_type = TRUE;
5564 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
5567 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
5568 WINED3DPRIMITIVETYPE *primitive_type)
5570 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5572 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
5574 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
5576 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
5579 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
5581 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5583 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
5585 if(!This->stateBlock->vertexDecl) {
5586 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5587 return WINED3DERR_INVALIDCALL;
5590 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5591 if(This->stateBlock->streamIsUP) {
5592 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5593 This->stateBlock->streamIsUP = FALSE;
5596 if(This->stateBlock->loadBaseVertexIndex != 0) {
5597 This->stateBlock->loadBaseVertexIndex = 0;
5598 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5600 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5601 drawPrimitive(iface, vertex_count, 0/* NumVertices */, StartVertex /* start_idx */,
5602 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5606 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5607 UINT minIndex, UINT NumVertices, UINT startIndex, UINT index_count)
5609 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5611 IWineD3DBuffer *pIB;
5614 pIB = This->stateBlock->pIndexData;
5616 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5617 * without an index buffer set. (The first time at least...)
5618 * D3D8 simply dies, but I doubt it can do much harm to return
5619 * D3DERR_INVALIDCALL there as well. */
5620 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5621 return WINED3DERR_INVALIDCALL;
5624 if(!This->stateBlock->vertexDecl) {
5625 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5626 return WINED3DERR_INVALIDCALL;
5629 if(This->stateBlock->streamIsUP) {
5630 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5631 This->stateBlock->streamIsUP = FALSE;
5633 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
5635 TRACE("(%p) : min %u, vertex count %u, startIdx %u, index count %u\n",
5636 This, minIndex, NumVertices, startIndex, index_count);
5638 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
5644 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5645 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5646 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5649 drawPrimitive(iface, index_count, NumVertices, startIndex, idxStride,
5650 vbo ? NULL : ((struct wined3d_buffer *) pIB)->resource.allocatedMemory, minIndex);
5655 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
5656 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5658 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5661 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
5662 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
5664 if(!This->stateBlock->vertexDecl) {
5665 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5666 return WINED3DERR_INVALIDCALL;
5669 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5670 vb = This->stateBlock->streamSource[0];
5671 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5672 if (vb) IWineD3DBuffer_Release(vb);
5673 This->stateBlock->streamOffset[0] = 0;
5674 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5675 This->stateBlock->streamIsUP = TRUE;
5676 This->stateBlock->loadBaseVertexIndex = 0;
5678 /* TODO: Only mark dirty if drawing from a different UP address */
5679 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5681 drawPrimitive(iface, vertex_count, 0 /* NumVertices */, 0 /* start_idx */,
5682 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5684 /* MSDN specifies stream zero settings must be set to NULL */
5685 This->stateBlock->streamStride[0] = 0;
5686 This->stateBlock->streamSource[0] = NULL;
5688 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5689 * the new stream sources or use UP drawing again
5694 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, UINT MinVertexIndex,
5695 UINT NumVertices, UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
5696 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5699 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5703 TRACE("(%p) : MinVtxIdx %u, NumVIdx %u, index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u\n",
5704 This, MinVertexIndex, NumVertices, index_count, pIndexData,
5705 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5707 if(!This->stateBlock->vertexDecl) {
5708 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5709 return WINED3DERR_INVALIDCALL;
5712 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
5718 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5719 vb = This->stateBlock->streamSource[0];
5720 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5721 if (vb) IWineD3DBuffer_Release(vb);
5722 This->stateBlock->streamIsUP = TRUE;
5723 This->stateBlock->streamOffset[0] = 0;
5724 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5726 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5727 This->stateBlock->baseVertexIndex = 0;
5728 This->stateBlock->loadBaseVertexIndex = 0;
5729 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5730 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5731 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5733 drawPrimitive(iface, index_count, NumVertices, 0 /* start_idx */,
5734 idxStride, pIndexData, MinVertexIndex);
5736 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5737 This->stateBlock->streamSource[0] = NULL;
5738 This->stateBlock->streamStride[0] = 0;
5739 ib = This->stateBlock->pIndexData;
5741 IWineD3DBuffer_Release(ib);
5742 This->stateBlock->pIndexData = NULL;
5744 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5745 * SetStreamSource to specify a vertex buffer
5751 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5752 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
5754 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5756 /* Mark the state dirty until we have nicer tracking
5757 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5760 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5761 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5762 This->stateBlock->baseVertexIndex = 0;
5763 This->up_strided = DrawPrimStrideData;
5764 drawPrimitive(iface, vertex_count, 0, 0, 0, NULL, 0);
5765 This->up_strided = NULL;
5769 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5770 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
5771 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
5773 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5774 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5776 /* Mark the state dirty until we have nicer tracking
5777 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5780 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5781 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5782 This->stateBlock->streamIsUP = TRUE;
5783 This->stateBlock->baseVertexIndex = 0;
5784 This->up_strided = DrawPrimStrideData;
5785 drawPrimitive(iface, vertex_count, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData, 0 /* minindex */);
5786 This->up_strided = NULL;
5790 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5791 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5792 * not callable by the app directly no parameter validation checks are needed here.
5794 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5795 WINED3DLOCKED_BOX src;
5796 WINED3DLOCKED_BOX dst;
5798 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5800 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5801 * dirtification to improve loading performance.
5803 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5804 if(FAILED(hr)) return hr;
5805 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5807 IWineD3DVolume_UnlockBox(pSourceVolume);
5811 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5813 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5815 IWineD3DVolume_UnlockBox(pSourceVolume);
5817 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5822 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5823 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5824 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5825 HRESULT hr = WINED3D_OK;
5826 WINED3DRESOURCETYPE sourceType;
5827 WINED3DRESOURCETYPE destinationType;
5830 /* TODO: think about moving the code into IWineD3DBaseTexture */
5832 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5834 /* verify that the source and destination textures aren't NULL */
5835 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5836 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5837 This, pSourceTexture, pDestinationTexture);
5838 hr = WINED3DERR_INVALIDCALL;
5841 if (pSourceTexture == pDestinationTexture) {
5842 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5843 This, pSourceTexture, pDestinationTexture);
5844 hr = WINED3DERR_INVALIDCALL;
5846 /* Verify that the source and destination textures are the same type */
5847 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5848 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5850 if (sourceType != destinationType) {
5851 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5853 hr = WINED3DERR_INVALIDCALL;
5856 /* check that both textures have the identical numbers of levels */
5857 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5858 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5859 hr = WINED3DERR_INVALIDCALL;
5862 if (WINED3D_OK == hr) {
5863 IWineD3DBaseTextureImpl *pDestImpl = (IWineD3DBaseTextureImpl *) pDestinationTexture;
5865 /* Make sure that the destination texture is loaded */
5866 pDestImpl->baseTexture.internal_preload(pDestinationTexture, SRGB_RGB);
5868 /* Update every surface level of the texture */
5869 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5871 switch (sourceType) {
5872 case WINED3DRTYPE_TEXTURE:
5874 IWineD3DSurface *srcSurface;
5875 IWineD3DSurface *destSurface;
5877 for (i = 0 ; i < levels ; ++i) {
5878 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5879 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5880 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5881 IWineD3DSurface_Release(srcSurface);
5882 IWineD3DSurface_Release(destSurface);
5883 if (WINED3D_OK != hr) {
5884 WARN("(%p) : Call to update surface failed\n", This);
5890 case WINED3DRTYPE_CUBETEXTURE:
5892 IWineD3DSurface *srcSurface;
5893 IWineD3DSurface *destSurface;
5894 WINED3DCUBEMAP_FACES faceType;
5896 for (i = 0 ; i < levels ; ++i) {
5897 /* Update each cube face */
5898 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5899 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5900 if (WINED3D_OK != hr) {
5901 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5903 TRACE("Got srcSurface %p\n", srcSurface);
5905 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5906 if (WINED3D_OK != hr) {
5907 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5909 TRACE("Got desrSurface %p\n", destSurface);
5911 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5912 IWineD3DSurface_Release(srcSurface);
5913 IWineD3DSurface_Release(destSurface);
5914 if (WINED3D_OK != hr) {
5915 WARN("(%p) : Call to update surface failed\n", This);
5923 case WINED3DRTYPE_VOLUMETEXTURE:
5925 IWineD3DVolume *srcVolume = NULL;
5926 IWineD3DVolume *destVolume = NULL;
5928 for (i = 0 ; i < levels ; ++i) {
5929 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5930 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5931 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5932 IWineD3DVolume_Release(srcVolume);
5933 IWineD3DVolume_Release(destVolume);
5934 if (WINED3D_OK != hr) {
5935 WARN("(%p) : Call to update volume failed\n", This);
5943 FIXME("(%p) : Unsupported source and destination type\n", This);
5944 hr = WINED3DERR_INVALIDCALL;
5951 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5952 IWineD3DSwapChain *swapChain;
5954 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5955 if(hr == WINED3D_OK) {
5956 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5957 IWineD3DSwapChain_Release(swapChain);
5962 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5963 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5964 IWineD3DBaseTextureImpl *texture;
5967 TRACE("(%p) : %p\n", This, pNumPasses);
5969 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5970 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5971 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5972 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5974 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5975 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5976 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5979 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5980 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5982 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5983 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5986 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5987 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5990 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5991 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5992 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5997 /* return a sensible default */
6000 TRACE("returning D3D_OK\n");
6004 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
6008 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
6009 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
6010 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8
6011 || texture->resource.format_desc->format == WINED3DFMT_A8P8))
6013 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
6018 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
6019 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6022 PALETTEENTRY **palettes;
6024 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6026 if (PaletteNumber >= MAX_PALETTES) {
6027 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6028 return WINED3DERR_INVALIDCALL;
6031 if (PaletteNumber >= This->NumberOfPalettes) {
6032 NewSize = This->NumberOfPalettes;
6035 } while(PaletteNumber >= NewSize);
6036 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
6038 ERR("Out of memory!\n");
6039 return E_OUTOFMEMORY;
6041 This->palettes = palettes;
6042 This->NumberOfPalettes = NewSize;
6045 if (!This->palettes[PaletteNumber]) {
6046 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
6047 if (!This->palettes[PaletteNumber]) {
6048 ERR("Out of memory!\n");
6049 return E_OUTOFMEMORY;
6053 for (j = 0; j < 256; ++j) {
6054 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
6055 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
6056 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
6057 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
6059 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
6060 TRACE("(%p) : returning\n", This);
6064 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
6065 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6067 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6068 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
6069 /* What happens in such situation isn't documented; Native seems to silently abort
6070 on such conditions. Return Invalid Call. */
6071 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
6072 return WINED3DERR_INVALIDCALL;
6074 for (j = 0; j < 256; ++j) {
6075 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
6076 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
6077 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
6078 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
6080 TRACE("(%p) : returning\n", This);
6084 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
6085 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6086 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6087 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
6088 (tested with reference rasterizer). Return Invalid Call. */
6089 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
6090 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
6091 return WINED3DERR_INVALIDCALL;
6093 /*TODO: stateblocks */
6094 if (This->currentPalette != PaletteNumber) {
6095 This->currentPalette = PaletteNumber;
6096 dirtify_p8_texture_samplers(This);
6098 TRACE("(%p) : returning\n", This);
6102 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
6103 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6104 if (PaletteNumber == NULL) {
6105 WARN("(%p) : returning Invalid Call\n", This);
6106 return WINED3DERR_INVALIDCALL;
6108 /*TODO: stateblocks */
6109 *PaletteNumber = This->currentPalette;
6110 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
6114 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
6115 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6119 FIXME("(%p) : stub\n", This);
6123 This->softwareVertexProcessing = bSoftware;
6128 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
6129 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6133 FIXME("(%p) : stub\n", This);
6136 return This->softwareVertexProcessing;
6140 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
6141 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6142 IWineD3DSwapChain *swapChain;
6145 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
6147 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
6148 if(hr == WINED3D_OK){
6149 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
6150 IWineD3DSwapChain_Release(swapChain);
6152 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
6158 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
6159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6161 if(nSegments != 0.0f) {
6164 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
6171 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
6172 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6176 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
6182 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
6183 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6184 /** TODO: remove casts to IWineD3DSurfaceImpl
6185 * NOTE: move code to surface to accomplish this
6186 ****************************************/
6187 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
6188 int srcWidth, srcHeight;
6189 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
6190 WINED3DFORMAT destFormat, srcFormat;
6192 int srcLeft, destLeft, destTop;
6193 WINED3DPOOL srcPool, destPool;
6195 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
6196 glDescriptor *glDescription = NULL;
6197 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
6201 CONVERT_TYPES convert = NO_CONVERSION;
6203 WINED3DSURFACE_DESC winedesc;
6205 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
6206 memset(&winedesc, 0, sizeof(winedesc));
6207 winedesc.Width = &srcSurfaceWidth;
6208 winedesc.Height = &srcSurfaceHeight;
6209 winedesc.Pool = &srcPool;
6210 winedesc.Format = &srcFormat;
6212 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6214 winedesc.Width = &destSurfaceWidth;
6215 winedesc.Height = &destSurfaceHeight;
6216 winedesc.Pool = &destPool;
6217 winedesc.Format = &destFormat;
6218 winedesc.Size = &destSize;
6220 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6222 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
6223 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
6224 return WINED3DERR_INVALIDCALL;
6227 /* This call loads the opengl surface directly, instead of copying the surface to the
6228 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
6229 * copy in sysmem and use regular surface loading.
6231 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
6232 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
6233 if(convert != NO_CONVERSION) {
6234 return IWineD3DSurface_BltFast(pDestinationSurface,
6235 pDestPoint ? pDestPoint->x : 0,
6236 pDestPoint ? pDestPoint->y : 0,
6237 pSourceSurface, pSourceRect, 0);
6240 if (destFormat == WINED3DFMT_UNKNOWN) {
6241 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6242 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6244 /* Get the update surface description */
6245 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6248 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6251 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6252 checkGLcall("glActiveTextureARB");
6255 /* Make sure the surface is loaded and up to date */
6256 surface_internal_preload(pDestinationSurface, SRGB_RGB);
6257 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
6259 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
6261 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
6262 dst_format_desc = ((IWineD3DSurfaceImpl *)pDestinationSurface)->resource.format_desc;
6264 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6265 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6266 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
6267 srcLeft = pSourceRect ? pSourceRect->left : 0;
6268 destLeft = pDestPoint ? pDestPoint->x : 0;
6269 destTop = pDestPoint ? pDestPoint->y : 0;
6272 /* This function doesn't support compressed textures
6273 the pitch is just bytesPerPixel * width */
6274 if(srcWidth != srcSurfaceWidth || srcLeft ){
6275 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
6276 offset += srcLeft * src_format_desc->byte_count;
6277 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6279 /* TODO DXT formats */
6281 if(pSourceRect != NULL && pSourceRect->top != 0){
6282 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
6284 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
6285 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
6286 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
6289 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6291 /* need to lock the surface to get the data */
6292 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6297 /* TODO: Cube and volume support */
6299 /* not a whole row so we have to do it a line at a time */
6302 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
6303 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6305 for (j = destTop; j < (srcHeight + destTop); ++j)
6307 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, j,
6308 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
6312 } else { /* Full width, so just write out the whole texture */
6313 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6315 if (WINED3DFMT_DXT1 == destFormat ||
6316 WINED3DFMT_DXT2 == destFormat ||
6317 WINED3DFMT_DXT3 == destFormat ||
6318 WINED3DFMT_DXT4 == destFormat ||
6319 WINED3DFMT_DXT5 == destFormat) {
6320 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6321 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6322 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
6323 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6324 } if (destFormat != srcFormat) {
6325 FIXME("Updating mixed format compressed texture is not curretly support\n");
6327 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
6328 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
6331 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6336 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
6337 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
6340 checkGLcall("glTexSubImage2D");
6344 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
6345 sampler = This->rev_tex_unit_map[0];
6346 if (sampler != -1) {
6347 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6353 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6354 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6355 struct WineD3DRectPatch *patch;
6356 GLenum old_primitive_type;
6360 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6362 if(!(Handle || pRectPatchInfo)) {
6363 /* TODO: Write a test for the return value, thus the FIXME */
6364 FIXME("Both Handle and pRectPatchInfo are NULL\n");
6365 return WINED3DERR_INVALIDCALL;
6369 i = PATCHMAP_HASHFUNC(Handle);
6371 LIST_FOR_EACH(e, &This->patches[i]) {
6372 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6373 if(patch->Handle == Handle) {
6380 TRACE("Patch does not exist. Creating a new one\n");
6381 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6382 patch->Handle = Handle;
6383 list_add_head(&This->patches[i], &patch->entry);
6385 TRACE("Found existing patch %p\n", patch);
6388 /* Since opengl does not load tesselated vertex attributes into numbered vertex
6389 * attributes we have to tesselate, read back, and draw. This needs a patch
6390 * management structure instance. Create one.
6392 * A possible improvement is to check if a vertex shader is used, and if not directly
6395 FIXME("Drawing an uncached patch. This is slow\n");
6396 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6399 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
6400 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
6401 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
6403 TRACE("Tesselation density or patch info changed, retesselating\n");
6405 if(pRectPatchInfo) {
6406 patch->RectPatchInfo = *pRectPatchInfo;
6408 patch->numSegs[0] = pNumSegs[0];
6409 patch->numSegs[1] = pNumSegs[1];
6410 patch->numSegs[2] = pNumSegs[2];
6411 patch->numSegs[3] = pNumSegs[3];
6413 hr = tesselate_rectpatch(This, patch);
6415 WARN("Patch tesselation failed\n");
6417 /* Do not release the handle to store the params of the patch */
6419 HeapFree(GetProcessHeap(), 0, patch);
6425 This->currentPatch = patch;
6426 old_primitive_type = This->stateBlock->gl_primitive_type;
6427 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
6428 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
6429 This->stateBlock->gl_primitive_type = old_primitive_type;
6430 This->currentPatch = NULL;
6432 /* Destroy uncached patches */
6434 HeapFree(GetProcessHeap(), 0, patch->mem);
6435 HeapFree(GetProcessHeap(), 0, patch);
6440 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6441 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6442 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6443 FIXME("(%p) : Stub\n", This);
6447 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6448 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6450 struct WineD3DRectPatch *patch;
6452 TRACE("(%p) Handle(%d)\n", This, Handle);
6454 i = PATCHMAP_HASHFUNC(Handle);
6455 LIST_FOR_EACH(e, &This->patches[i]) {
6456 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6457 if(patch->Handle == Handle) {
6458 TRACE("Deleting patch %p\n", patch);
6459 list_remove(&patch->entry);
6460 HeapFree(GetProcessHeap(), 0, patch->mem);
6461 HeapFree(GetProcessHeap(), 0, patch);
6466 /* TODO: Write a test for the return value */
6467 FIXME("Attempt to destroy nonexistent patch\n");
6468 return WINED3DERR_INVALIDCALL;
6471 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6473 IWineD3DSwapChain *swapchain;
6475 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6476 if (SUCCEEDED(hr)) {
6477 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6484 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
6485 const WINED3DRECT *rect, const float color[4])
6487 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6488 IWineD3DSwapChain *swapchain;
6490 swapchain = get_swapchain(surface);
6494 TRACE("Surface %p is onscreen\n", surface);
6496 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6498 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6499 buffer = surface_get_gl_buffer(surface, swapchain);
6500 glDrawBuffer(buffer);
6501 checkGLcall("glDrawBuffer()");
6503 TRACE("Surface %p is offscreen\n", surface);
6505 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6507 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6508 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6509 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6510 checkGLcall("glFramebufferRenderbufferEXT");
6514 glEnable(GL_SCISSOR_TEST);
6516 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6518 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6519 rect->x2 - rect->x1, rect->y2 - rect->y1);
6521 checkGLcall("glScissor");
6522 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6524 glDisable(GL_SCISSOR_TEST);
6526 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6528 glDisable(GL_BLEND);
6529 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6531 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6532 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6534 glClearColor(color[0], color[1], color[2], color[3]);
6535 glClear(GL_COLOR_BUFFER_BIT);
6536 checkGLcall("glClear");
6538 if (This->activeContext->current_fbo) {
6539 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6541 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6542 checkGLcall("glBindFramebuffer()");
6545 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6546 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6547 glDrawBuffer(GL_BACK);
6548 checkGLcall("glDrawBuffer()");
6554 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6555 unsigned int r, g, b, a;
6558 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6559 destfmt == WINED3DFMT_R8G8B8)
6562 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6564 a = (color & 0xff000000) >> 24;
6565 r = (color & 0x00ff0000) >> 16;
6566 g = (color & 0x0000ff00) >> 8;
6567 b = (color & 0x000000ff) >> 0;
6571 case WINED3DFMT_R5G6B5:
6572 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6579 TRACE("Returning %08x\n", ret);
6582 case WINED3DFMT_X1R5G5B5:
6583 case WINED3DFMT_A1R5G5B5:
6592 TRACE("Returning %08x\n", ret);
6595 case WINED3DFMT_A8_UNORM:
6596 TRACE("Returning %08x\n", a);
6599 case WINED3DFMT_X4R4G4B4:
6600 case WINED3DFMT_A4R4G4B4:
6609 TRACE("Returning %08x\n", ret);
6612 case WINED3DFMT_R3G3B2:
6619 TRACE("Returning %08x\n", ret);
6622 case WINED3DFMT_X8B8G8R8:
6623 case WINED3DFMT_R8G8B8A8_UNORM:
6628 TRACE("Returning %08x\n", ret);
6631 case WINED3DFMT_A2R10G10B10:
6633 r = (r * 1024) / 256;
6634 g = (g * 1024) / 256;
6635 b = (b * 1024) / 256;
6640 TRACE("Returning %08x\n", ret);
6643 case WINED3DFMT_R10G10B10A2_UNORM:
6645 r = (r * 1024) / 256;
6646 g = (g * 1024) / 256;
6647 b = (b * 1024) / 256;
6652 TRACE("Returning %08x\n", ret);
6656 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6661 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6662 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6663 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6665 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6667 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6668 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6669 return WINED3DERR_INVALIDCALL;
6672 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6673 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
6674 color_fill_fbo(iface, pSurface, pRect, c);
6677 /* Just forward this to the DirectDraw blitting engine */
6678 memset(&BltFx, 0, sizeof(BltFx));
6679 BltFx.dwSize = sizeof(BltFx);
6680 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
6681 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6682 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6686 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
6687 IWineD3DRendertargetView *rendertarget_view, const float color[4])
6689 IWineD3DResource *resource;
6690 IWineD3DSurface *surface;
6693 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
6696 ERR("Failed to get resource, hr %#x\n", hr);
6700 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
6702 FIXME("Only supported on surface resources\n");
6703 IWineD3DResource_Release(resource);
6707 surface = (IWineD3DSurface *)resource;
6709 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6711 color_fill_fbo(iface, surface, NULL, color);
6718 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
6720 c = ((DWORD)(color[2] * 255.0));
6721 c |= ((DWORD)(color[1] * 255.0)) << 8;
6722 c |= ((DWORD)(color[0] * 255.0)) << 16;
6723 c |= ((DWORD)(color[3] * 255.0)) << 24;
6725 /* Just forward this to the DirectDraw blitting engine */
6726 memset(&BltFx, 0, sizeof(BltFx));
6727 BltFx.dwSize = sizeof(BltFx);
6728 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
6729 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6732 ERR("Blt failed, hr %#x\n", hr);
6736 IWineD3DResource_Release(resource);
6739 /* rendertarget and depth stencil functions */
6740 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6741 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6743 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6744 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6745 return WINED3DERR_INVALIDCALL;
6748 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6749 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6750 /* Note inc ref on returned surface */
6751 if(*ppRenderTarget != NULL)
6752 IWineD3DSurface_AddRef(*ppRenderTarget);
6756 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6757 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6758 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6759 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6760 IWineD3DSwapChainImpl *Swapchain;
6763 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6765 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6766 if(hr != WINED3D_OK) {
6767 ERR("Can't get the swapchain\n");
6771 /* Make sure to release the swapchain */
6772 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6774 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6775 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6776 return WINED3DERR_INVALIDCALL;
6778 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6779 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6780 return WINED3DERR_INVALIDCALL;
6783 if(Swapchain->frontBuffer != Front) {
6784 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6786 if(Swapchain->frontBuffer)
6788 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6789 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
6791 Swapchain->frontBuffer = Front;
6793 if(Swapchain->frontBuffer) {
6794 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6795 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
6799 if(Back && !Swapchain->backBuffer) {
6800 /* We need memory for the back buffer array - only one back buffer this way */
6801 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6802 if(!Swapchain->backBuffer) {
6803 ERR("Out of memory\n");
6804 return E_OUTOFMEMORY;
6808 if(Swapchain->backBuffer[0] != Back) {
6809 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6811 /* What to do about the context here in the case of multithreading? Not sure.
6812 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6815 if(!Swapchain->backBuffer[0]) {
6816 /* GL was told to draw to the front buffer at creation,
6819 glDrawBuffer(GL_BACK);
6820 checkGLcall("glDrawBuffer(GL_BACK)");
6821 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6822 Swapchain->presentParms.BackBufferCount = 1;
6824 /* That makes problems - disable for now */
6825 /* glDrawBuffer(GL_FRONT); */
6826 checkGLcall("glDrawBuffer(GL_FRONT)");
6827 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6828 Swapchain->presentParms.BackBufferCount = 0;
6832 if(Swapchain->backBuffer[0])
6834 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6835 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
6837 Swapchain->backBuffer[0] = Back;
6839 if(Swapchain->backBuffer[0]) {
6840 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6841 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
6843 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6844 Swapchain->backBuffer = NULL;
6852 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6853 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6854 *ppZStencilSurface = This->stencilBufferTarget;
6855 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6857 if(*ppZStencilSurface != NULL) {
6858 /* Note inc ref on returned surface */
6859 IWineD3DSurface_AddRef(*ppZStencilSurface);
6862 return WINED3DERR_NOTFOUND;
6866 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6867 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6869 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6870 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6871 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6873 POINT offset = {0, 0};
6875 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6876 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6877 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6878 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6881 case WINED3DTEXF_LINEAR:
6882 gl_filter = GL_LINEAR;
6886 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6887 case WINED3DTEXF_NONE:
6888 case WINED3DTEXF_POINT:
6889 gl_filter = GL_NEAREST;
6893 /* Attach src surface to src fbo */
6894 src_swapchain = get_swapchain(src_surface);
6895 if (src_swapchain) {
6896 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6898 TRACE("Source surface %p is onscreen\n", src_surface);
6899 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6900 /* Make sure the drawable is up to date. In the offscreen case
6901 * attach_surface_fbo() implicitly takes care of this. */
6902 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6904 if(buffer == GL_FRONT) {
6907 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6908 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6909 h = windowsize.bottom - windowsize.top;
6910 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6911 src_rect->y1 = offset.y + h - src_rect->y1;
6912 src_rect->y2 = offset.y + h - src_rect->y2;
6914 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6915 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6919 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6920 glReadBuffer(buffer);
6921 checkGLcall("glReadBuffer()");
6923 TRACE("Source surface %p is offscreen\n", src_surface);
6925 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6926 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6927 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6928 checkGLcall("glReadBuffer()");
6929 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6930 checkGLcall("glFramebufferRenderbufferEXT");
6934 /* Attach dst surface to dst fbo */
6935 dst_swapchain = get_swapchain(dst_surface);
6936 if (dst_swapchain) {
6937 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6939 TRACE("Destination surface %p is onscreen\n", dst_surface);
6940 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6941 /* Make sure the drawable is up to date. In the offscreen case
6942 * attach_surface_fbo() implicitly takes care of this. */
6943 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6945 if(buffer == GL_FRONT) {
6948 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6949 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6950 h = windowsize.bottom - windowsize.top;
6951 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6952 dst_rect->y1 = offset.y + h - dst_rect->y1;
6953 dst_rect->y2 = offset.y + h - dst_rect->y2;
6955 /* Screen coords = window coords, surface height = window height */
6956 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6957 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6961 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6962 glDrawBuffer(buffer);
6963 checkGLcall("glDrawBuffer()");
6965 TRACE("Destination surface %p is offscreen\n", dst_surface);
6967 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6968 if(!src_swapchain) {
6969 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6973 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6974 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6975 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6976 checkGLcall("glDrawBuffer()");
6977 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6978 checkGLcall("glFramebufferRenderbufferEXT");
6980 glDisable(GL_SCISSOR_TEST);
6981 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6984 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6985 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6986 checkGLcall("glBlitFramebuffer()");
6988 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6989 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6990 checkGLcall("glBlitFramebuffer()");
6993 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6995 if (This->activeContext->current_fbo) {
6996 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6998 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6999 checkGLcall("glBindFramebuffer()");
7002 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
7003 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
7004 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
7005 glDrawBuffer(GL_BACK);
7006 checkGLcall("glDrawBuffer()");
7011 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
7012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7013 WINED3DVIEWPORT viewport;
7015 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
7017 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
7018 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
7019 This, RenderTargetIndex, GL_LIMITS(buffers));
7020 return WINED3DERR_INVALIDCALL;
7023 /* MSDN says that null disables the render target
7024 but a device must always be associated with a render target
7025 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
7027 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
7028 FIXME("Trying to set render target 0 to NULL\n");
7029 return WINED3DERR_INVALIDCALL;
7031 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
7032 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);
7033 return WINED3DERR_INVALIDCALL;
7036 /* If we are trying to set what we already have, don't bother */
7037 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
7038 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7041 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
7042 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
7043 This->render_targets[RenderTargetIndex] = pRenderTarget;
7045 /* Render target 0 is special */
7046 if(RenderTargetIndex == 0) {
7047 /* Finally, reset the viewport as the MSDN states. */
7048 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
7049 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
7052 viewport.MaxZ = 1.0f;
7053 viewport.MinZ = 0.0f;
7054 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
7055 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
7056 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
7058 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
7063 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
7064 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7065 HRESULT hr = WINED3D_OK;
7066 IWineD3DSurface *tmp;
7068 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
7070 if (pNewZStencil == This->stencilBufferTarget) {
7071 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7073 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
7074 * depending on the renter target implementation being used.
7075 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
7076 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7077 * stencil buffer and incur an extra memory overhead
7078 ******************************************************/
7080 if (This->stencilBufferTarget) {
7081 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
7082 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
7083 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
7085 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
7086 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
7087 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
7091 tmp = This->stencilBufferTarget;
7092 This->stencilBufferTarget = pNewZStencil;
7093 /* should we be calling the parent or the wined3d surface? */
7094 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
7095 if (NULL != tmp) IWineD3DSurface_Release(tmp);
7098 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
7099 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
7100 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
7101 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
7102 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
7109 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
7110 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
7111 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7112 /* TODO: the use of Impl is deprecated. */
7113 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
7114 WINED3DLOCKED_RECT lockedRect;
7116 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
7118 /* some basic validation checks */
7119 if(This->cursorTexture) {
7120 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7122 glDeleteTextures(1, &This->cursorTexture);
7124 This->cursorTexture = 0;
7127 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
7128 This->haveHardwareCursor = TRUE;
7130 This->haveHardwareCursor = FALSE;
7133 WINED3DLOCKED_RECT rect;
7135 /* MSDN: Cursor must be A8R8G8B8 */
7136 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format_desc->format)
7138 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
7139 return WINED3DERR_INVALIDCALL;
7142 /* MSDN: Cursor must be smaller than the display mode */
7143 if(pSur->currentDesc.Width > This->ddraw_width ||
7144 pSur->currentDesc.Height > This->ddraw_height) {
7145 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);
7146 return WINED3DERR_INVALIDCALL;
7149 if (!This->haveHardwareCursor) {
7150 /* TODO: MSDN: Cursor sizes must be a power of 2 */
7152 /* Do not store the surface's pointer because the application may
7153 * release it after setting the cursor image. Windows doesn't
7154 * addref the set surface, so we can't do this either without
7155 * creating circular refcount dependencies. Copy out the gl texture
7158 This->cursorWidth = pSur->currentDesc.Width;
7159 This->cursorHeight = pSur->currentDesc.Height;
7160 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
7162 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION);
7163 char *mem, *bits = rect.pBits;
7164 GLint intfmt = glDesc->glInternal;
7165 GLint format = glDesc->glFormat;
7166 GLint type = glDesc->glType;
7167 INT height = This->cursorHeight;
7168 INT width = This->cursorWidth;
7169 INT bpp = glDesc->byte_count;
7172 /* Reformat the texture memory (pitch and width can be
7174 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
7175 for(i = 0; i < height; i++)
7176 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
7177 IWineD3DSurface_UnlockRect(pCursorBitmap);
7180 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
7181 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
7182 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
7185 /* Make sure that a proper texture unit is selected */
7186 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
7187 checkGLcall("glActiveTextureARB");
7188 sampler = This->rev_tex_unit_map[0];
7189 if (sampler != -1) {
7190 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
7192 /* Create a new cursor texture */
7193 glGenTextures(1, &This->cursorTexture);
7194 checkGLcall("glGenTextures");
7195 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
7196 checkGLcall("glBindTexture");
7197 /* Copy the bitmap memory into the cursor texture */
7198 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
7199 HeapFree(GetProcessHeap(), 0, mem);
7200 checkGLcall("glTexImage2D");
7202 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
7203 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
7204 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
7211 FIXME("A cursor texture was not returned.\n");
7212 This->cursorTexture = 0;
7217 /* Draw a hardware cursor */
7218 ICONINFO cursorInfo;
7220 /* Create and clear maskBits because it is not needed for
7221 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
7223 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
7224 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
7225 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
7226 WINED3DLOCK_NO_DIRTY_UPDATE |
7227 WINED3DLOCK_READONLY
7229 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
7230 pSur->currentDesc.Height);
7232 cursorInfo.fIcon = FALSE;
7233 cursorInfo.xHotspot = XHotSpot;
7234 cursorInfo.yHotspot = YHotSpot;
7235 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
7236 pSur->currentDesc.Height, 1,
7238 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
7239 pSur->currentDesc.Height, 1,
7240 32, lockedRect.pBits);
7241 IWineD3DSurface_UnlockRect(pCursorBitmap);
7242 /* Create our cursor and clean up. */
7243 cursor = CreateIconIndirect(&cursorInfo);
7245 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
7246 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
7247 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
7248 This->hardwareCursor = cursor;
7249 HeapFree(GetProcessHeap(), 0, maskBits);
7253 This->xHotSpot = XHotSpot;
7254 This->yHotSpot = YHotSpot;
7258 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7259 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7260 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7262 This->xScreenSpace = XScreenSpace;
7263 This->yScreenSpace = YScreenSpace;
7269 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7270 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7271 BOOL oldVisible = This->bCursorVisible;
7274 TRACE("(%p) : visible(%d)\n", This, bShow);
7277 * When ShowCursor is first called it should make the cursor appear at the OS's last
7278 * known cursor position. Because of this, some applications just repetitively call
7279 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
7282 This->xScreenSpace = pt.x;
7283 This->yScreenSpace = pt.y;
7285 if (This->haveHardwareCursor) {
7286 This->bCursorVisible = bShow;
7288 SetCursor(This->hardwareCursor);
7294 if (This->cursorTexture)
7295 This->bCursorVisible = bShow;
7301 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7302 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7303 IWineD3DResourceImpl *resource;
7304 TRACE("(%p) : state (%u)\n", This, This->state);
7306 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
7307 switch (This->state) {
7310 case WINED3DERR_DEVICELOST:
7312 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7313 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
7314 return WINED3DERR_DEVICENOTRESET;
7316 return WINED3DERR_DEVICELOST;
7318 case WINED3DERR_DRIVERINTERNALERROR:
7319 return WINED3DERR_DRIVERINTERNALERROR;
7323 return WINED3DERR_DRIVERINTERNALERROR;
7327 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7329 /** FIXME: Resource tracking needs to be done,
7330 * The closes we can do to this is set the priorities of all managed textures low
7331 * and then reset them.
7332 ***********************************************************/
7333 FIXME("(%p) : stub\n", This);
7337 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
7339 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
7341 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7342 if(surface->Flags & SFLAG_DIBSECTION) {
7343 /* Release the DC */
7344 SelectObject(surface->hDC, surface->dib.holdbitmap);
7345 DeleteDC(surface->hDC);
7346 /* Release the DIB section */
7347 DeleteObject(surface->dib.DIBsection);
7348 surface->dib.bitmap_data = NULL;
7349 surface->resource.allocatedMemory = NULL;
7350 surface->Flags &= ~SFLAG_DIBSECTION;
7352 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7353 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7354 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
7355 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
7356 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7357 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7359 surface->pow2Width = surface->pow2Height = 1;
7360 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7361 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7363 surface->glRect.left = 0;
7364 surface->glRect.top = 0;
7365 surface->glRect.right = surface->pow2Width;
7366 surface->glRect.bottom = surface->pow2Height;
7368 if(surface->glDescription.textureName) {
7369 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7371 glDeleteTextures(1, &surface->glDescription.textureName);
7373 surface->glDescription.textureName = 0;
7374 surface->Flags &= ~SFLAG_CLIENT;
7376 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7377 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7378 surface->Flags |= SFLAG_NONPOW2;
7380 surface->Flags &= ~SFLAG_NONPOW2;
7382 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7383 surface->resource.allocatedMemory = NULL;
7384 surface->resource.heapMemory = NULL;
7385 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7386 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7387 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7388 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7390 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7394 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7395 TRACE("Unloading resource %p\n", resource);
7396 IWineD3DResource_UnLoad(resource);
7397 IWineD3DResource_Release(resource);
7401 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
7404 WINED3DDISPLAYMODE m;
7407 /* All Windowed modes are supported, as is leaving the current mode */
7408 if(pp->Windowed) return TRUE;
7409 if(!pp->BackBufferWidth) return TRUE;
7410 if(!pp->BackBufferHeight) return TRUE;
7412 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7413 for(i = 0; i < count; i++) {
7414 memset(&m, 0, sizeof(m));
7415 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7417 ERR("EnumAdapterModes failed\n");
7419 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7420 /* Mode found, it is supported */
7424 /* Mode not found -> not supported */
7428 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7429 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7430 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7432 IWineD3DBaseShaderImpl *shader;
7434 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7435 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7436 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7440 if(This->depth_blt_texture) {
7441 glDeleteTextures(1, &This->depth_blt_texture);
7442 This->depth_blt_texture = 0;
7444 if (This->depth_blt_rb) {
7445 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7446 This->depth_blt_rb = 0;
7447 This->depth_blt_rb_w = 0;
7448 This->depth_blt_rb_h = 0;
7452 This->blitter->free_private(iface);
7453 This->frag_pipe->free_private(iface);
7454 This->shader_backend->shader_free_private(iface);
7457 for (i = 0; i < GL_LIMITS(textures); i++) {
7458 /* Textures are recreated below */
7459 glDeleteTextures(1, &This->dummyTextureName[i]);
7460 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7461 This->dummyTextureName[i] = 0;
7465 while(This->numContexts) {
7466 DestroyContext(This, This->contexts[0]);
7468 This->activeContext = NULL;
7469 HeapFree(GetProcessHeap(), 0, swapchain->context);
7470 swapchain->context = NULL;
7471 swapchain->num_contexts = 0;
7474 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7475 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7476 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7478 IWineD3DSurfaceImpl *target;
7480 /* Recreate the primary swapchain's context */
7481 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7482 if(swapchain->backBuffer) {
7483 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7485 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7487 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7488 &swapchain->presentParms);
7489 swapchain->num_contexts = 1;
7490 This->activeContext = swapchain->context[0];
7492 create_dummy_textures(This);
7494 hr = This->shader_backend->shader_alloc_private(iface);
7496 ERR("Failed to recreate shader private data\n");
7499 hr = This->frag_pipe->alloc_private(iface);
7501 TRACE("Fragment pipeline private data couldn't be allocated\n");
7504 hr = This->blitter->alloc_private(iface);
7506 TRACE("Blitter private data couldn't be allocated\n");
7513 This->blitter->free_private(iface);
7514 This->frag_pipe->free_private(iface);
7515 This->shader_backend->shader_free_private(iface);
7519 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7520 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7521 IWineD3DSwapChainImpl *swapchain;
7523 BOOL DisplayModeChanged = FALSE;
7524 WINED3DDISPLAYMODE mode;
7525 TRACE("(%p)\n", This);
7527 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7529 ERR("Failed to get the first implicit swapchain\n");
7533 if(!is_display_mode_supported(This, pPresentationParameters)) {
7534 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7535 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7536 pPresentationParameters->BackBufferHeight);
7537 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
7538 return WINED3DERR_INVALIDCALL;
7541 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7542 * on an existing gl context, so there's no real need for recreation.
7544 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7546 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7548 TRACE("New params:\n");
7549 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7550 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7551 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7552 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7553 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7554 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7555 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7556 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7557 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7558 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7559 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7560 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7561 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7563 /* No special treatment of these parameters. Just store them */
7564 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7565 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7566 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7567 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7569 /* What to do about these? */
7570 if(pPresentationParameters->BackBufferCount != 0 &&
7571 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7572 ERR("Cannot change the back buffer count yet\n");
7574 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7575 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7576 ERR("Cannot change the back buffer format yet\n");
7578 if(pPresentationParameters->hDeviceWindow != NULL &&
7579 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7580 ERR("Cannot change the device window yet\n");
7582 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7585 TRACE("Creating the depth stencil buffer\n");
7587 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
7589 pPresentationParameters->BackBufferWidth,
7590 pPresentationParameters->BackBufferHeight,
7591 pPresentationParameters->AutoDepthStencilFormat,
7592 pPresentationParameters->MultiSampleType,
7593 pPresentationParameters->MultiSampleQuality,
7595 &This->auto_depth_stencil_buffer);
7598 ERR("Failed to create the depth stencil buffer\n");
7599 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7600 return WINED3DERR_INVALIDCALL;
7604 /* Reset the depth stencil */
7605 if (pPresentationParameters->EnableAutoDepthStencil)
7606 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7608 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7610 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7612 if(pPresentationParameters->Windowed) {
7613 mode.Width = swapchain->orig_width;
7614 mode.Height = swapchain->orig_height;
7615 mode.RefreshRate = 0;
7616 mode.Format = swapchain->presentParms.BackBufferFormat;
7618 mode.Width = pPresentationParameters->BackBufferWidth;
7619 mode.Height = pPresentationParameters->BackBufferHeight;
7620 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7621 mode.Format = swapchain->presentParms.BackBufferFormat;
7624 /* Should Width == 800 && Height == 0 set 800x600? */
7625 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7626 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7627 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7631 if(!pPresentationParameters->Windowed) {
7632 DisplayModeChanged = TRUE;
7634 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7635 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7637 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7638 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7639 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7641 if(This->auto_depth_stencil_buffer) {
7642 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7646 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7647 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7648 DisplayModeChanged) {
7650 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7652 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7653 if(swapchain->presentParms.Windowed) {
7654 /* switch from windowed to fs */
7655 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7656 pPresentationParameters->BackBufferWidth,
7657 pPresentationParameters->BackBufferHeight);
7659 /* Fullscreen -> fullscreen mode change */
7660 MoveWindow(swapchain->win_handle, 0, 0,
7661 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7664 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7665 /* Fullscreen -> windowed switch */
7666 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7668 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7669 } else if(!pPresentationParameters->Windowed) {
7670 DWORD style = This->style, exStyle = This->exStyle;
7671 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7672 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7673 * Reset to clear up their mess. Guild Wars also loses the device during that.
7677 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7678 pPresentationParameters->BackBufferWidth,
7679 pPresentationParameters->BackBufferHeight);
7680 This->style = style;
7681 This->exStyle = exStyle;
7684 TRACE("Resetting stateblock\n");
7685 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
7686 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
7688 /* Note: No parent needed for initial internal stateblock */
7689 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
7690 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7691 else TRACE("Created stateblock %p\n", This->stateBlock);
7692 This->updateStateBlock = This->stateBlock;
7693 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
7695 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7697 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7700 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7701 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7703 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7709 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7710 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7711 /** FIXME: always true at the moment **/
7712 if(!bEnableDialogs) {
7713 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7719 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7720 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7721 TRACE("(%p) : pParameters %p\n", This, pParameters);
7723 *pParameters = This->createParms;
7727 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7728 IWineD3DSwapChain *swapchain;
7730 TRACE("Relaying to swapchain\n");
7732 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7733 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7734 IWineD3DSwapChain_Release(swapchain);
7739 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7740 IWineD3DSwapChain *swapchain;
7742 TRACE("Relaying to swapchain\n");
7744 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7745 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7746 IWineD3DSwapChain_Release(swapchain);
7752 /** ********************************************************
7753 * Notification functions
7754 ** ********************************************************/
7755 /** This function must be called in the release of a resource when ref == 0,
7756 * the contents of resource must still be correct,
7757 * any handles to other resource held by the caller must be closed
7758 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7759 *****************************************************/
7760 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7762 TRACE("(%p) : Adding resource %p\n", This, resource);
7764 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7767 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7769 TRACE("(%p) : Removing resource %p\n", This, resource);
7771 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7774 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7776 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7779 TRACE("(%p) : resource %p\n", This, resource);
7781 context_resource_released((IWineD3DDevice *)This, resource, type);
7784 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7785 case WINED3DRTYPE_SURFACE: {
7788 /* Cleanup any FBO attachments if d3d is enabled */
7789 if(This->d3d_initialized) {
7790 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7791 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7793 TRACE("Last active render target destroyed\n");
7794 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7795 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7796 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7797 * and the lastActiveRenderTarget member shouldn't matter
7800 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7801 TRACE("Activating primary back buffer\n");
7802 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7803 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7804 /* Single buffering environment */
7805 TRACE("Activating primary front buffer\n");
7806 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7808 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7809 /* Implicit render target destroyed, that means the device is being destroyed
7810 * whatever we set here, it shouldn't matter
7812 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7815 /* May happen during ddraw uninitialization */
7816 TRACE("Render target set, but swapchain does not exist!\n");
7817 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7821 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7822 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7823 This->render_targets[i] = NULL;
7826 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7827 This->stencilBufferTarget = NULL;
7833 case WINED3DRTYPE_TEXTURE:
7834 case WINED3DRTYPE_CUBETEXTURE:
7835 case WINED3DRTYPE_VOLUMETEXTURE:
7836 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7837 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7838 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7839 This->stateBlock->textures[counter] = NULL;
7841 if (This->updateStateBlock != This->stateBlock ){
7842 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7843 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7844 This->updateStateBlock->textures[counter] = NULL;
7849 case WINED3DRTYPE_VOLUME:
7850 /* TODO: nothing really? */
7852 case WINED3DRTYPE_BUFFER:
7855 TRACE("Cleaning up stream pointers\n");
7857 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7858 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7859 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7861 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7862 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7863 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7864 This->updateStateBlock->streamSource[streamNumber] = 0;
7865 /* Set changed flag? */
7868 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) */
7869 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7870 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7871 This->stateBlock->streamSource[streamNumber] = 0;
7876 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7877 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7878 This->updateStateBlock->pIndexData = NULL;
7881 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7882 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7883 This->stateBlock->pIndexData = NULL;
7890 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7895 /* Remove the resource from the resourceStore */
7896 device_resource_remove(This, resource);
7898 TRACE("Resource released\n");
7902 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7903 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7904 IWineD3DResourceImpl *resource, *cursor;
7906 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7908 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7909 TRACE("enumerating resource %p\n", resource);
7910 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7911 ret = pCallback((IWineD3DResource *) resource, pData);
7912 if(ret == S_FALSE) {
7913 TRACE("Canceling enumeration\n");
7920 /**********************************************************
7921 * IWineD3DDevice VTbl follows
7922 **********************************************************/
7924 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7926 /*** IUnknown methods ***/
7927 IWineD3DDeviceImpl_QueryInterface,
7928 IWineD3DDeviceImpl_AddRef,
7929 IWineD3DDeviceImpl_Release,
7930 /*** IWineD3DDevice methods ***/
7931 IWineD3DDeviceImpl_GetParent,
7932 /*** Creation methods**/
7933 IWineD3DDeviceImpl_CreateBuffer,
7934 IWineD3DDeviceImpl_CreateVertexBuffer,
7935 IWineD3DDeviceImpl_CreateIndexBuffer,
7936 IWineD3DDeviceImpl_CreateStateBlock,
7937 IWineD3DDeviceImpl_CreateSurface,
7938 IWineD3DDeviceImpl_CreateRendertargetView,
7939 IWineD3DDeviceImpl_CreateTexture,
7940 IWineD3DDeviceImpl_CreateVolumeTexture,
7941 IWineD3DDeviceImpl_CreateVolume,
7942 IWineD3DDeviceImpl_CreateCubeTexture,
7943 IWineD3DDeviceImpl_CreateQuery,
7944 IWineD3DDeviceImpl_CreateSwapChain,
7945 IWineD3DDeviceImpl_CreateVertexDeclaration,
7946 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7947 IWineD3DDeviceImpl_CreateVertexShader,
7948 IWineD3DDeviceImpl_CreatePixelShader,
7949 IWineD3DDeviceImpl_CreatePalette,
7950 /*** Odd functions **/
7951 IWineD3DDeviceImpl_Init3D,
7952 IWineD3DDeviceImpl_InitGDI,
7953 IWineD3DDeviceImpl_Uninit3D,
7954 IWineD3DDeviceImpl_UninitGDI,
7955 IWineD3DDeviceImpl_SetMultithreaded,
7956 IWineD3DDeviceImpl_EvictManagedResources,
7957 IWineD3DDeviceImpl_GetAvailableTextureMem,
7958 IWineD3DDeviceImpl_GetBackBuffer,
7959 IWineD3DDeviceImpl_GetCreationParameters,
7960 IWineD3DDeviceImpl_GetDeviceCaps,
7961 IWineD3DDeviceImpl_GetDirect3D,
7962 IWineD3DDeviceImpl_GetDisplayMode,
7963 IWineD3DDeviceImpl_SetDisplayMode,
7964 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7965 IWineD3DDeviceImpl_GetRasterStatus,
7966 IWineD3DDeviceImpl_GetSwapChain,
7967 IWineD3DDeviceImpl_Reset,
7968 IWineD3DDeviceImpl_SetDialogBoxMode,
7969 IWineD3DDeviceImpl_SetCursorProperties,
7970 IWineD3DDeviceImpl_SetCursorPosition,
7971 IWineD3DDeviceImpl_ShowCursor,
7972 IWineD3DDeviceImpl_TestCooperativeLevel,
7973 /*** Getters and setters **/
7974 IWineD3DDeviceImpl_SetClipPlane,
7975 IWineD3DDeviceImpl_GetClipPlane,
7976 IWineD3DDeviceImpl_SetClipStatus,
7977 IWineD3DDeviceImpl_GetClipStatus,
7978 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7979 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7980 IWineD3DDeviceImpl_SetDepthStencilSurface,
7981 IWineD3DDeviceImpl_GetDepthStencilSurface,
7982 IWineD3DDeviceImpl_SetGammaRamp,
7983 IWineD3DDeviceImpl_GetGammaRamp,
7984 IWineD3DDeviceImpl_SetIndices,
7985 IWineD3DDeviceImpl_GetIndices,
7986 IWineD3DDeviceImpl_SetBaseVertexIndex,
7987 IWineD3DDeviceImpl_GetBaseVertexIndex,
7988 IWineD3DDeviceImpl_SetLight,
7989 IWineD3DDeviceImpl_GetLight,
7990 IWineD3DDeviceImpl_SetLightEnable,
7991 IWineD3DDeviceImpl_GetLightEnable,
7992 IWineD3DDeviceImpl_SetMaterial,
7993 IWineD3DDeviceImpl_GetMaterial,
7994 IWineD3DDeviceImpl_SetNPatchMode,
7995 IWineD3DDeviceImpl_GetNPatchMode,
7996 IWineD3DDeviceImpl_SetPaletteEntries,
7997 IWineD3DDeviceImpl_GetPaletteEntries,
7998 IWineD3DDeviceImpl_SetPixelShader,
7999 IWineD3DDeviceImpl_GetPixelShader,
8000 IWineD3DDeviceImpl_SetPixelShaderConstantB,
8001 IWineD3DDeviceImpl_GetPixelShaderConstantB,
8002 IWineD3DDeviceImpl_SetPixelShaderConstantI,
8003 IWineD3DDeviceImpl_GetPixelShaderConstantI,
8004 IWineD3DDeviceImpl_SetPixelShaderConstantF,
8005 IWineD3DDeviceImpl_GetPixelShaderConstantF,
8006 IWineD3DDeviceImpl_SetRenderState,
8007 IWineD3DDeviceImpl_GetRenderState,
8008 IWineD3DDeviceImpl_SetRenderTarget,
8009 IWineD3DDeviceImpl_GetRenderTarget,
8010 IWineD3DDeviceImpl_SetFrontBackBuffers,
8011 IWineD3DDeviceImpl_SetSamplerState,
8012 IWineD3DDeviceImpl_GetSamplerState,
8013 IWineD3DDeviceImpl_SetScissorRect,
8014 IWineD3DDeviceImpl_GetScissorRect,
8015 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
8016 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
8017 IWineD3DDeviceImpl_SetStreamSource,
8018 IWineD3DDeviceImpl_GetStreamSource,
8019 IWineD3DDeviceImpl_SetStreamSourceFreq,
8020 IWineD3DDeviceImpl_GetStreamSourceFreq,
8021 IWineD3DDeviceImpl_SetTexture,
8022 IWineD3DDeviceImpl_GetTexture,
8023 IWineD3DDeviceImpl_SetTextureStageState,
8024 IWineD3DDeviceImpl_GetTextureStageState,
8025 IWineD3DDeviceImpl_SetTransform,
8026 IWineD3DDeviceImpl_GetTransform,
8027 IWineD3DDeviceImpl_SetVertexDeclaration,
8028 IWineD3DDeviceImpl_GetVertexDeclaration,
8029 IWineD3DDeviceImpl_SetVertexShader,
8030 IWineD3DDeviceImpl_GetVertexShader,
8031 IWineD3DDeviceImpl_SetVertexShaderConstantB,
8032 IWineD3DDeviceImpl_GetVertexShaderConstantB,
8033 IWineD3DDeviceImpl_SetVertexShaderConstantI,
8034 IWineD3DDeviceImpl_GetVertexShaderConstantI,
8035 IWineD3DDeviceImpl_SetVertexShaderConstantF,
8036 IWineD3DDeviceImpl_GetVertexShaderConstantF,
8037 IWineD3DDeviceImpl_SetViewport,
8038 IWineD3DDeviceImpl_GetViewport,
8039 IWineD3DDeviceImpl_MultiplyTransform,
8040 IWineD3DDeviceImpl_ValidateDevice,
8041 IWineD3DDeviceImpl_ProcessVertices,
8042 /*** State block ***/
8043 IWineD3DDeviceImpl_BeginStateBlock,
8044 IWineD3DDeviceImpl_EndStateBlock,
8045 /*** Scene management ***/
8046 IWineD3DDeviceImpl_BeginScene,
8047 IWineD3DDeviceImpl_EndScene,
8048 IWineD3DDeviceImpl_Present,
8049 IWineD3DDeviceImpl_Clear,
8050 IWineD3DDeviceImpl_ClearRendertargetView,
8052 IWineD3DDeviceImpl_SetPrimitiveType,
8053 IWineD3DDeviceImpl_GetPrimitiveType,
8054 IWineD3DDeviceImpl_DrawPrimitive,
8055 IWineD3DDeviceImpl_DrawIndexedPrimitive,
8056 IWineD3DDeviceImpl_DrawPrimitiveUP,
8057 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
8058 IWineD3DDeviceImpl_DrawPrimitiveStrided,
8059 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
8060 IWineD3DDeviceImpl_DrawRectPatch,
8061 IWineD3DDeviceImpl_DrawTriPatch,
8062 IWineD3DDeviceImpl_DeletePatch,
8063 IWineD3DDeviceImpl_ColorFill,
8064 IWineD3DDeviceImpl_UpdateTexture,
8065 IWineD3DDeviceImpl_UpdateSurface,
8066 IWineD3DDeviceImpl_GetFrontBufferData,
8067 /*** object tracking ***/
8068 IWineD3DDeviceImpl_EnumResources
8071 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
8072 WINED3DRS_ALPHABLENDENABLE ,
8073 WINED3DRS_ALPHAFUNC ,
8074 WINED3DRS_ALPHAREF ,
8075 WINED3DRS_ALPHATESTENABLE ,
8077 WINED3DRS_COLORWRITEENABLE ,
8078 WINED3DRS_DESTBLEND ,
8079 WINED3DRS_DITHERENABLE ,
8080 WINED3DRS_FILLMODE ,
8081 WINED3DRS_FOGDENSITY ,
8083 WINED3DRS_FOGSTART ,
8084 WINED3DRS_LASTPIXEL ,
8085 WINED3DRS_SHADEMODE ,
8086 WINED3DRS_SRCBLEND ,
8087 WINED3DRS_STENCILENABLE ,
8088 WINED3DRS_STENCILFAIL ,
8089 WINED3DRS_STENCILFUNC ,
8090 WINED3DRS_STENCILMASK ,
8091 WINED3DRS_STENCILPASS ,
8092 WINED3DRS_STENCILREF ,
8093 WINED3DRS_STENCILWRITEMASK ,
8094 WINED3DRS_STENCILZFAIL ,
8095 WINED3DRS_TEXTUREFACTOR ,
8106 WINED3DRS_ZWRITEENABLE
8109 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
8110 WINED3DTSS_ALPHAARG0 ,
8111 WINED3DTSS_ALPHAARG1 ,
8112 WINED3DTSS_ALPHAARG2 ,
8113 WINED3DTSS_ALPHAOP ,
8114 WINED3DTSS_BUMPENVLOFFSET ,
8115 WINED3DTSS_BUMPENVLSCALE ,
8116 WINED3DTSS_BUMPENVMAT00 ,
8117 WINED3DTSS_BUMPENVMAT01 ,
8118 WINED3DTSS_BUMPENVMAT10 ,
8119 WINED3DTSS_BUMPENVMAT11 ,
8120 WINED3DTSS_COLORARG0 ,
8121 WINED3DTSS_COLORARG1 ,
8122 WINED3DTSS_COLORARG2 ,
8123 WINED3DTSS_COLOROP ,
8124 WINED3DTSS_RESULTARG ,
8125 WINED3DTSS_TEXCOORDINDEX ,
8126 WINED3DTSS_TEXTURETRANSFORMFLAGS
8129 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
8130 WINED3DSAMP_ADDRESSU ,
8131 WINED3DSAMP_ADDRESSV ,
8132 WINED3DSAMP_ADDRESSW ,
8133 WINED3DSAMP_BORDERCOLOR ,
8134 WINED3DSAMP_MAGFILTER ,
8135 WINED3DSAMP_MINFILTER ,
8136 WINED3DSAMP_MIPFILTER ,
8137 WINED3DSAMP_MIPMAPLODBIAS ,
8138 WINED3DSAMP_MAXMIPLEVEL ,
8139 WINED3DSAMP_MAXANISOTROPY ,
8140 WINED3DSAMP_SRGBTEXTURE ,
8141 WINED3DSAMP_ELEMENTINDEX
8144 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
8146 WINED3DRS_AMBIENTMATERIALSOURCE ,
8147 WINED3DRS_CLIPPING ,
8148 WINED3DRS_CLIPPLANEENABLE ,
8149 WINED3DRS_COLORVERTEX ,
8150 WINED3DRS_DIFFUSEMATERIALSOURCE ,
8151 WINED3DRS_EMISSIVEMATERIALSOURCE ,
8152 WINED3DRS_FOGDENSITY ,
8154 WINED3DRS_FOGSTART ,
8155 WINED3DRS_FOGTABLEMODE ,
8156 WINED3DRS_FOGVERTEXMODE ,
8157 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
8158 WINED3DRS_LIGHTING ,
8159 WINED3DRS_LOCALVIEWER ,
8160 WINED3DRS_MULTISAMPLEANTIALIAS ,
8161 WINED3DRS_MULTISAMPLEMASK ,
8162 WINED3DRS_NORMALIZENORMALS ,
8163 WINED3DRS_PATCHEDGESTYLE ,
8164 WINED3DRS_POINTSCALE_A ,
8165 WINED3DRS_POINTSCALE_B ,
8166 WINED3DRS_POINTSCALE_C ,
8167 WINED3DRS_POINTSCALEENABLE ,
8168 WINED3DRS_POINTSIZE ,
8169 WINED3DRS_POINTSIZE_MAX ,
8170 WINED3DRS_POINTSIZE_MIN ,
8171 WINED3DRS_POINTSPRITEENABLE ,
8172 WINED3DRS_RANGEFOGENABLE ,
8173 WINED3DRS_SPECULARMATERIALSOURCE ,
8174 WINED3DRS_TWEENFACTOR ,
8175 WINED3DRS_VERTEXBLEND ,
8176 WINED3DRS_CULLMODE ,
8180 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8181 WINED3DTSS_TEXCOORDINDEX ,
8182 WINED3DTSS_TEXTURETRANSFORMFLAGS
8185 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8186 WINED3DSAMP_DMAPOFFSET
8189 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
8190 DWORD rep = This->StateTable[state].representative;
8194 WineD3DContext *context;
8197 for(i = 0; i < This->numContexts; i++) {
8198 context = This->contexts[i];
8199 if(isStateDirty(context, rep)) continue;
8201 context->dirtyArray[context->numDirtyEntries++] = rep;
8204 context->isStateDirty[idx] |= (1 << shift);
8208 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8209 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8210 /* The drawable size of a pbuffer render target is the current pbuffer size
8212 *width = dev->pbufferWidth;
8213 *height = dev->pbufferHeight;
8216 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8217 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
8219 *width = This->pow2Width;
8220 *height = This->pow2Height;
8223 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8224 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8225 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
8226 * current context's drawable, which is the size of the back buffer of the swapchain
8227 * the active context belongs to. The back buffer of the swapchain is stored as the
8228 * surface the context belongs to.
8230 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
8231 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;