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);
903 TRACE("(%p) Create surface\n",This);
905 if(MultisampleQuality > 0) {
906 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
907 MultisampleQuality=0;
910 /** FIXME: Check that the format is supported
912 *******************************/
914 if (WINED3DFMT_UNKNOWN == Format) {
917 else if (glDesc->Flags & WINED3DFMT_FLAG_COMPRESSED)
919 UINT row_block_count = (Width + glDesc->block_width - 1) / glDesc->block_width;
920 UINT row_count = (Height + glDesc->block_height - 1) / glDesc->block_height;
921 Size = row_count * row_block_count * glDesc->block_byte_count;
925 /* The pitch is a multiple of 4 bytes */
926 Size = ((Width * glDesc->byte_count) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
930 if(glDesc->heightscale != 0.0) Size *= glDesc->heightscale;
932 /** Create and initialise the surface resource **/
933 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
936 ERR("Out of memory\n");
938 return WINED3DERR_OUTOFVIDEOMEMORY;
941 /* Look at the implementation and set the correct Vtable */
945 /* Check if a 3D adapter is available when creating gl surfaces */
948 ERR("OpenGL surfaces are not available without opengl\n");
949 HeapFree(GetProcessHeap(), 0, object);
950 return WINED3DERR_NOTAVAILABLE;
952 object->lpVtbl = &IWineD3DSurface_Vtbl;
956 object->lpVtbl = &IWineGDISurface_Vtbl;
960 /* To be sure to catch this */
961 ERR("Unknown requested surface implementation %d!\n", Impl);
962 HeapFree(GetProcessHeap(), 0, object);
963 return WINED3DERR_INVALIDCALL;
966 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_SURFACE, This, Size, Usage, glDesc, Pool, parent);
969 WARN("Failed to initialize resource, returning %#x\n", hr);
970 HeapFree(GetProcessHeap(), 0, object);
975 TRACE("(%p) : Created resource %p\n", This, object);
977 *ppSurface = (IWineD3DSurface *)object;
979 /* "Standalone" surface */
980 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
982 object->currentDesc.Width = Width;
983 object->currentDesc.Height = Height;
984 object->currentDesc.MultiSampleType = MultiSample;
985 object->currentDesc.MultiSampleQuality = MultisampleQuality;
986 object->glDescription.level = Level;
987 list_init(&object->overlays);
990 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
991 object->Flags |= Discard ? SFLAG_DISCARD : 0;
992 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
993 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
995 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
997 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
998 * this function is too deep to need to care about things like this.
999 * Levels need to be checked too, and possibly Type since they all affect what can be done.
1000 * ****************************************/
1002 case WINED3DPOOL_SCRATCH:
1004 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
1005 "which are mutually exclusive, setting lockable to TRUE\n");
1008 case WINED3DPOOL_SYSTEMMEM:
1009 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
1010 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
1011 case WINED3DPOOL_MANAGED:
1012 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
1013 "Usage of DYNAMIC which are mutually exclusive, not doing "
1014 "anything just telling you.\n");
1016 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
1017 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
1018 && !(Usage & WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
1019 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
1022 FIXME("(%p) Unknown pool %d\n", This, Pool);
1026 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
1027 FIXME("Trying to create a render target that isn't in the default pool\n");
1030 /* mark the texture as dirty so that it gets loaded first time around*/
1031 surface_add_dirty_rect(*ppSurface, NULL);
1032 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
1033 This, Width, Height, Format, debug_d3dformat(Format),
1034 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
1036 list_init(&object->renderbuffers);
1038 /* Call the private setup routine */
1039 hr = IWineD3DSurface_PrivateSetup((IWineD3DSurface *)object);
1042 ERR("Private setup failed, returning %#x\n", hr);
1043 IWineD3DSurface_Release(*ppSurface);
1051 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
1052 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
1054 struct wined3d_rendertarget_view *object;
1056 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1059 ERR("Failed to allocate memory\n");
1060 return E_OUTOFMEMORY;
1063 object->vtbl = &wined3d_rendertarget_view_vtbl;
1064 object->refcount = 1;
1065 IWineD3DResource_AddRef(resource);
1066 object->resource = resource;
1067 object->parent = parent;
1069 *rendertarget_view = (IWineD3DRendertargetView *)object;
1074 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
1075 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
1076 WINED3DPOOL Pool, IWineD3DTexture **ppTexture, IUnknown *parent)
1078 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1079 IWineD3DTextureImpl *object;
1082 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1083 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
1084 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
1086 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1089 ERR("Out of memory\n");
1091 return WINED3DERR_OUTOFVIDEOMEMORY;
1094 object->lpVtbl = &IWineD3DTexture_Vtbl;
1096 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent);
1099 WARN("Failed to initialize texture, returning %#x\n", hr);
1100 HeapFree(GetProcessHeap(), 0, object);
1105 *ppTexture = (IWineD3DTexture *)object;
1107 TRACE("(%p) : Created texture %p\n", This, object);
1112 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1113 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
1114 WINED3DPOOL Pool, IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent)
1116 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1117 IWineD3DVolumeTextureImpl *object;
1120 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1121 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1123 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1126 ERR("Out of memory\n");
1127 *ppVolumeTexture = NULL;
1128 return WINED3DERR_OUTOFVIDEOMEMORY;
1131 object->lpVtbl = &IWineD3DVolumeTexture_Vtbl;
1132 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent);
1135 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
1136 HeapFree(GetProcessHeap(), 0, object);
1137 *ppVolumeTexture = NULL;
1141 TRACE("(%p) : Created volume texture %p.\n", This, object);
1142 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
1147 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1148 UINT Width, UINT Height, UINT Depth, DWORD Usage, WINED3DFORMAT Format,
1149 WINED3DPOOL Pool, IWineD3DVolume **ppVolume, IUnknown *parent)
1151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1152 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1153 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &GLINFO_LOCATION);
1156 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1157 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1158 return WINED3DERR_INVALIDCALL;
1161 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1164 ERR("Out of memory\n");
1166 return WINED3DERR_OUTOFVIDEOMEMORY;
1169 object->lpVtbl = &IWineD3DVolume_Vtbl;
1170 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_VOLUME, This,
1171 Width * Height * Depth * format_desc->byte_count, Usage, format_desc, Pool, parent);
1174 WARN("Failed to initialize resource, returning %#x\n", hr);
1175 HeapFree(GetProcessHeap(), 0, object);
1180 TRACE("(%p) : Created resource %p\n", This, object);
1182 *ppVolume = (IWineD3DVolume *)object;
1184 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1185 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1187 object->currentDesc.Width = Width;
1188 object->currentDesc.Height = Height;
1189 object->currentDesc.Depth = Depth;
1191 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1192 object->lockable = TRUE;
1193 object->locked = FALSE;
1194 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1195 object->dirty = TRUE;
1197 volume_add_dirty_box((IWineD3DVolume *)object, NULL);
1202 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface,
1203 UINT EdgeLength, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
1204 WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture, IUnknown *parent)
1206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1207 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1210 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1213 ERR("Out of memory\n");
1214 *ppCubeTexture = NULL;
1215 return WINED3DERR_OUTOFVIDEOMEMORY;
1218 object->lpVtbl = &IWineD3DCubeTexture_Vtbl;
1219 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent);
1222 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1223 HeapFree(GetProcessHeap(), 0, object);
1224 *ppCubeTexture = NULL;
1228 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1229 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1234 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1235 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1236 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1237 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1238 const IWineD3DQueryVtbl *vtable;
1240 /* Just a check to see if we support this type of query */
1242 case WINED3DQUERYTYPE_OCCLUSION:
1243 TRACE("(%p) occlusion query\n", This);
1244 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1247 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1249 vtable = &IWineD3DOcclusionQuery_Vtbl;
1252 case WINED3DQUERYTYPE_EVENT:
1253 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1254 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1255 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1257 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1259 vtable = &IWineD3DEventQuery_Vtbl;
1263 case WINED3DQUERYTYPE_VCACHE:
1264 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1265 case WINED3DQUERYTYPE_VERTEXSTATS:
1266 case WINED3DQUERYTYPE_TIMESTAMP:
1267 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1268 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1269 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1270 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1271 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1272 case WINED3DQUERYTYPE_PIXELTIMINGS:
1273 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1274 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1276 /* Use the base Query vtable until we have a special one for each query */
1277 vtable = &IWineD3DQuery_Vtbl;
1278 FIXME("(%p) Unhandled query type %d\n", This, Type);
1280 if(NULL == ppQuery || hr != WINED3D_OK) {
1284 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1287 ERR("Out of memory\n");
1289 return WINED3DERR_OUTOFVIDEOMEMORY;
1292 object->lpVtbl = vtable;
1293 object->type = Type;
1294 object->state = QUERY_CREATED;
1295 object->wineD3DDevice = This;
1296 object->parent = parent;
1299 *ppQuery = (IWineD3DQuery *)object;
1301 /* allocated the 'extended' data based on the type of query requested */
1303 case WINED3DQUERYTYPE_OCCLUSION:
1304 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1305 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1307 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1308 TRACE("(%p) Allocating data for an occlusion query\n", This);
1310 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1312 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1316 case WINED3DQUERYTYPE_EVENT:
1317 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1318 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1320 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1322 if(GL_SUPPORT(APPLE_FENCE)) {
1323 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1324 checkGLcall("glGenFencesAPPLE");
1325 } else if(GL_SUPPORT(NV_FENCE)) {
1326 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1327 checkGLcall("glGenFencesNV");
1332 case WINED3DQUERYTYPE_VCACHE:
1333 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1334 case WINED3DQUERYTYPE_VERTEXSTATS:
1335 case WINED3DQUERYTYPE_TIMESTAMP:
1336 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1337 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1338 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1339 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1340 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1341 case WINED3DQUERYTYPE_PIXELTIMINGS:
1342 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1343 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1345 object->extendedData = 0;
1346 FIXME("(%p) Unhandled query type %d\n",This , Type);
1348 TRACE("(%p) : Created Query %p\n", This, object);
1352 /*****************************************************************************
1353 * IWineD3DDeviceImpl_SetupFullscreenWindow
1355 * Helper function that modifies a HWND's Style and ExStyle for proper
1359 * iface: Pointer to the IWineD3DDevice interface
1360 * window: Window to setup
1362 *****************************************************************************/
1363 static LONG fullscreen_style(LONG orig_style) {
1364 LONG style = orig_style;
1365 style &= ~WS_CAPTION;
1366 style &= ~WS_THICKFRAME;
1368 /* Make sure the window is managed, otherwise we won't get keyboard input */
1369 style |= WS_POPUP | WS_SYSMENU;
1374 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1375 LONG exStyle = orig_exStyle;
1377 /* Filter out window decorations */
1378 exStyle &= ~WS_EX_WINDOWEDGE;
1379 exStyle &= ~WS_EX_CLIENTEDGE;
1384 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1387 LONG style, exStyle;
1388 /* Don't do anything if an original style is stored.
1389 * That shouldn't happen
1391 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1392 if (This->style || This->exStyle) {
1393 ERR("(%p): Want to change the window parameters of HWND %p, but "
1394 "another style is stored for restoration afterwards\n", This, window);
1397 /* Get the parameters and save them */
1398 style = GetWindowLongW(window, GWL_STYLE);
1399 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1400 This->style = style;
1401 This->exStyle = exStyle;
1403 style = fullscreen_style(style);
1404 exStyle = fullscreen_exStyle(exStyle);
1406 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1407 This->style, This->exStyle, style, exStyle);
1409 SetWindowLongW(window, GWL_STYLE, style);
1410 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1412 /* Inform the window about the update. */
1413 SetWindowPos(window, HWND_TOP, 0, 0,
1414 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1417 /*****************************************************************************
1418 * IWineD3DDeviceImpl_RestoreWindow
1420 * Helper function that restores a windows' properties when taking it out
1421 * of fullscreen mode
1424 * iface: Pointer to the IWineD3DDevice interface
1425 * window: Window to setup
1427 *****************************************************************************/
1428 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1429 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1430 LONG style, exStyle;
1432 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1433 * switch, do nothing
1435 if (!This->style && !This->exStyle) return;
1437 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1438 This, window, This->style, This->exStyle);
1440 style = GetWindowLongW(window, GWL_STYLE);
1441 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1443 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1444 * Some applications change it before calling Reset() when switching between windowed and
1445 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1447 if(style == fullscreen_style(This->style) &&
1448 exStyle == fullscreen_style(This->exStyle)) {
1449 SetWindowLongW(window, GWL_STYLE, This->style);
1450 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1453 /* Delete the old values */
1457 /* Inform the window about the update */
1458 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1459 0, 0, 0, 0, /* Pos, Size, ignored */
1460 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1463 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1464 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1465 WINED3DPRESENT_PARAMETERS *pPresentationParameters, IWineD3DSwapChain **ppSwapChain,
1466 IUnknown *parent, WINED3DSURFTYPE surface_type)
1468 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1471 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1473 IUnknown *bufferParent;
1474 BOOL displaymode_set = FALSE;
1475 WINED3DDISPLAYMODE Mode;
1476 const struct GlPixelFormatDesc *format_desc;
1478 TRACE("(%p) : Created Additional Swap Chain\n", This);
1480 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1481 * does a device hold a reference to a swap chain giving them a lifetime of the device
1482 * or does the swap chain notify the device of its destruction.
1483 *******************************/
1485 /* Check the params */
1486 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1487 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1488 return WINED3DERR_INVALIDCALL;
1489 } else if (pPresentationParameters->BackBufferCount > 1) {
1490 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");
1493 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1496 ERR("Out of memory\n");
1497 *ppSwapChain = NULL;
1498 return WINED3DERR_OUTOFVIDEOMEMORY;
1501 switch(surface_type) {
1503 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1505 case SURFACE_OPENGL:
1506 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1508 case SURFACE_UNKNOWN:
1509 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1510 HeapFree(GetProcessHeap(), 0, object);
1511 return WINED3DERR_INVALIDCALL;
1513 object->wineD3DDevice = This;
1514 object->parent = parent;
1517 *ppSwapChain = (IWineD3DSwapChain *)object;
1519 /*********************
1520 * Lookup the window Handle and the relating X window handle
1521 ********************/
1523 /* Setup hwnd we are using, plus which display this equates to */
1524 object->win_handle = pPresentationParameters->hDeviceWindow;
1525 if (!object->win_handle) {
1526 object->win_handle = This->createParms.hFocusWindow;
1528 if(!pPresentationParameters->Windowed && object->win_handle) {
1529 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1530 pPresentationParameters->BackBufferWidth,
1531 pPresentationParameters->BackBufferHeight);
1534 hDc = GetDC(object->win_handle);
1535 TRACE("Using hDc %p\n", hDc);
1538 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1539 return WINED3DERR_NOTAVAILABLE;
1542 /* Get info on the current display setup */
1543 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1544 object->orig_width = Mode.Width;
1545 object->orig_height = Mode.Height;
1546 object->orig_fmt = Mode.Format;
1547 format_desc = getFormatDescEntry(Mode.Format, &GLINFO_LOCATION);
1549 if (pPresentationParameters->Windowed &&
1550 ((pPresentationParameters->BackBufferWidth == 0) ||
1551 (pPresentationParameters->BackBufferHeight == 0) ||
1552 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1555 GetClientRect(object->win_handle, &Rect);
1557 if (pPresentationParameters->BackBufferWidth == 0) {
1558 pPresentationParameters->BackBufferWidth = Rect.right;
1559 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1561 if (pPresentationParameters->BackBufferHeight == 0) {
1562 pPresentationParameters->BackBufferHeight = Rect.bottom;
1563 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1565 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1566 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1567 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1571 /* Put the correct figures in the presentation parameters */
1572 TRACE("Copying across presentation parameters\n");
1573 object->presentParms = *pPresentationParameters;
1575 TRACE("calling rendertarget CB\n");
1576 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1577 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1578 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1579 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->frontBuffer);
1580 if (SUCCEEDED(hr)) {
1581 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1582 ((IWineD3DSurfaceImpl *)object->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
1583 if(surface_type == SURFACE_OPENGL) {
1584 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1587 ERR("Failed to create the front buffer\n");
1591 /*********************
1592 * Windowed / Fullscreen
1593 *******************/
1596 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1597 * so we should really check to see if there is a fullscreen swapchain already
1598 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1599 **************************************/
1601 if (!pPresentationParameters->Windowed) {
1602 WINED3DDISPLAYMODE mode;
1605 /* Change the display settings */
1606 mode.Width = pPresentationParameters->BackBufferWidth;
1607 mode.Height = pPresentationParameters->BackBufferHeight;
1608 mode.Format = pPresentationParameters->BackBufferFormat;
1609 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1611 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1612 displaymode_set = TRUE;
1616 * Create an opengl context for the display visual
1617 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1618 * use different properties after that point in time. FIXME: How to handle when requested format
1619 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1620 * it chooses is identical to the one already being used!
1621 **********************************/
1622 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1624 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1625 if(!object->context) {
1626 ERR("Failed to create the context array\n");
1630 object->num_contexts = 1;
1632 if(surface_type == SURFACE_OPENGL) {
1633 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1634 if (!object->context[0]) {
1635 ERR("Failed to create a new context\n");
1636 hr = WINED3DERR_NOTAVAILABLE;
1639 TRACE("Context created (HWND=%p, glContext=%p)\n",
1640 object->win_handle, object->context[0]->glCtx);
1644 /*********************
1645 * Create the back, front and stencil buffers
1646 *******************/
1647 if(object->presentParms.BackBufferCount > 0) {
1650 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1651 if(!object->backBuffer) {
1652 ERR("Out of memory\n");
1657 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1658 TRACE("calling rendertarget CB\n");
1659 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1660 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1661 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1662 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->backBuffer[i]);
1664 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1665 ((IWineD3DSurfaceImpl *)object->backBuffer[i])->Flags |= SFLAG_SWAPCHAIN;
1667 ERR("Cannot create new back buffer\n");
1670 if(surface_type == SURFACE_OPENGL) {
1672 glDrawBuffer(GL_BACK);
1673 checkGLcall("glDrawBuffer(GL_BACK)");
1678 object->backBuffer = NULL;
1680 /* Single buffering - draw to front buffer */
1681 if(surface_type == SURFACE_OPENGL) {
1683 glDrawBuffer(GL_FRONT);
1684 checkGLcall("glDrawBuffer(GL_FRONT)");
1689 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1690 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1691 TRACE("Creating depth stencil buffer\n");
1692 if (This->auto_depth_stencil_buffer == NULL ) {
1693 hr = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent, parent,
1694 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1695 object->presentParms.AutoDepthStencilFormat, object->presentParms.MultiSampleType,
1696 object->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */,
1697 &This->auto_depth_stencil_buffer);
1698 if (SUCCEEDED(hr)) {
1699 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1701 ERR("Failed to create the auto depth stencil\n");
1707 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1709 TRACE("Created swapchain %p\n", object);
1710 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1714 if (displaymode_set) {
1718 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1721 /* Change the display settings */
1722 memset(&devmode, 0, sizeof(devmode));
1723 devmode.dmSize = sizeof(devmode);
1724 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1725 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1726 devmode.dmPelsWidth = object->orig_width;
1727 devmode.dmPelsHeight = object->orig_height;
1728 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1731 if (object->backBuffer) {
1733 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1734 if(object->backBuffer[i]) {
1735 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1736 IUnknown_Release(bufferParent); /* once for the get parent */
1737 if (IUnknown_Release(bufferParent) > 0) {
1738 FIXME("(%p) Something's still holding the back buffer\n",This);
1742 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1743 object->backBuffer = NULL;
1745 if(object->context && object->context[0])
1746 DestroyContext(This, object->context[0]);
1747 if(object->frontBuffer) {
1748 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1749 IUnknown_Release(bufferParent); /* once for the get parent */
1750 if (IUnknown_Release(bufferParent) > 0) {
1751 FIXME("(%p) Something's still holding the front buffer\n",This);
1754 HeapFree(GetProcessHeap(), 0, object);
1758 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1759 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1760 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1761 TRACE("(%p)\n", This);
1763 return This->NumberOfSwapChains;
1766 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1767 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1768 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1770 if(iSwapChain < This->NumberOfSwapChains) {
1771 *pSwapChain = This->swapchains[iSwapChain];
1772 IWineD3DSwapChain_AddRef(*pSwapChain);
1773 TRACE("(%p) returning %p\n", This, *pSwapChain);
1776 TRACE("Swapchain out of range\n");
1778 return WINED3DERR_INVALIDCALL;
1783 * Vertex Declaration
1785 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1786 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1787 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1788 IWineD3DVertexDeclarationImpl *object = NULL;
1789 HRESULT hr = WINED3D_OK;
1791 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1792 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1794 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1797 ERR("Out of memory\n");
1798 *ppVertexDeclaration = NULL;
1799 return WINED3DERR_OUTOFVIDEOMEMORY;
1802 object->lpVtbl = &IWineD3DVertexDeclaration_Vtbl;
1803 object->wineD3DDevice = This;
1804 object->parent = parent;
1807 *ppVertexDeclaration = (IWineD3DVertexDeclaration *)object;
1809 hr = vertexdeclaration_init(object, elements, element_count);
1812 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
1813 *ppVertexDeclaration = NULL;
1819 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1820 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1822 unsigned int idx, idx2;
1823 unsigned int offset;
1824 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1825 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1826 BOOL has_blend_idx = has_blend &&
1827 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1828 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1829 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1830 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1831 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1832 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1833 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1835 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1836 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1837 WINED3DVERTEXELEMENT *elements = NULL;
1840 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1841 if (has_blend_idx) num_blends--;
1843 /* Compute declaration size */
1844 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1845 has_psize + has_diffuse + has_specular + num_textures;
1847 /* convert the declaration */
1848 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1849 if (!elements) return ~0U;
1853 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1854 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1855 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
1857 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1858 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1859 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1862 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1863 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1865 elements[idx].usage_idx = 0;
1868 if (has_blend && (num_blends > 0)) {
1869 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1870 elements[idx].format = WINED3DFMT_A8R8G8B8;
1872 switch(num_blends) {
1873 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
1874 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
1875 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
1876 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
1878 ERR("Unexpected amount of blend values: %u\n", num_blends);
1881 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1882 elements[idx].usage_idx = 0;
1885 if (has_blend_idx) {
1886 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1887 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1888 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
1889 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1890 elements[idx].format = WINED3DFMT_A8R8G8B8;
1892 elements[idx].format = WINED3DFMT_R32_FLOAT;
1893 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
1894 elements[idx].usage_idx = 0;
1898 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1899 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
1900 elements[idx].usage_idx = 0;
1904 elements[idx].format = WINED3DFMT_R32_FLOAT;
1905 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
1906 elements[idx].usage_idx = 0;
1910 elements[idx].format = WINED3DFMT_A8R8G8B8;
1911 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1912 elements[idx].usage_idx = 0;
1916 elements[idx].format = WINED3DFMT_A8R8G8B8;
1917 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1918 elements[idx].usage_idx = 1;
1921 for (idx2 = 0; idx2 < num_textures; idx2++) {
1922 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1923 switch (numcoords) {
1924 case WINED3DFVF_TEXTUREFORMAT1:
1925 elements[idx].format = WINED3DFMT_R32_FLOAT;
1927 case WINED3DFVF_TEXTUREFORMAT2:
1928 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
1930 case WINED3DFVF_TEXTUREFORMAT3:
1931 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1933 case WINED3DFVF_TEXTUREFORMAT4:
1934 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1937 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
1938 elements[idx].usage_idx = idx2;
1942 /* Now compute offsets, and initialize the rest of the fields */
1943 for (idx = 0, offset = 0; idx < size; ++idx)
1945 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
1946 elements[idx].input_slot = 0;
1947 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1948 elements[idx].offset = offset;
1949 offset += format_desc->component_count * format_desc->component_size;
1952 *ppVertexElements = elements;
1956 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1957 WINED3DVERTEXELEMENT* elements = NULL;
1958 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1962 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1963 if (size == ~0U) return WINED3DERR_OUTOFVIDEOMEMORY;
1965 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1966 HeapFree(GetProcessHeap(), 0, elements);
1967 if (hr != S_OK) return hr;
1972 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1973 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1974 IWineD3DVertexShader **ppVertexShader, IUnknown *parent)
1976 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1977 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1978 HRESULT hr = WINED3D_OK;
1980 if (!pFunction) return WINED3DERR_INVALIDCALL;
1982 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1985 ERR("Out of memory\n");
1986 *ppVertexShader = NULL;
1987 return WINED3DERR_OUTOFVIDEOMEMORY;
1990 object->lpVtbl = &IWineD3DVertexShader_Vtbl;
1991 object->parent = parent;
1992 shader_init(&object->baseShader, iface);
1993 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1994 *ppVertexShader = (IWineD3DVertexShader *)object;
1996 TRACE("(%p) : Created vertex shader %p\n", This, *ppVertexShader);
1998 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction, output_signature);
2001 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2002 IWineD3DVertexShader_Release(*ppVertexShader);
2003 *ppVertexShader = NULL;
2010 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
2011 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
2012 IWineD3DPixelShader **ppPixelShader, IUnknown *parent)
2014 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2015 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
2016 HRESULT hr = WINED3D_OK;
2018 if (!pFunction) return WINED3DERR_INVALIDCALL;
2020 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2023 ERR("Out of memory\n");
2024 *ppPixelShader = NULL;
2025 return WINED3DERR_OUTOFVIDEOMEMORY;
2028 object->lpVtbl = &IWineD3DPixelShader_Vtbl;
2029 object->parent = parent;
2030 shader_init(&object->baseShader, iface);
2031 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2032 *ppPixelShader = (IWineD3DPixelShader *)object;
2034 TRACE("(%p) : Created pixel shader %p\n", This, *ppPixelShader);
2036 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction, output_signature);
2039 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2040 IWineD3DPixelShader_Release(*ppPixelShader);
2041 *ppPixelShader = NULL;
2048 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
2049 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
2051 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2052 IWineD3DPaletteImpl *object;
2054 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
2056 /* Create the new object */
2057 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
2059 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
2060 return E_OUTOFMEMORY;
2063 object->lpVtbl = &IWineD3DPalette_Vtbl;
2065 object->Flags = Flags;
2066 object->parent = Parent;
2067 object->wineD3DDevice = This;
2068 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2069 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2072 HeapFree( GetProcessHeap(), 0, object);
2073 return E_OUTOFMEMORY;
2076 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2078 IWineD3DPalette_Release((IWineD3DPalette *) object);
2082 *Palette = (IWineD3DPalette *) object;
2087 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
2091 HDC dcb = NULL, dcs = NULL;
2092 WINEDDCOLORKEY colorkey;
2094 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
2097 GetObjectA(hbm, sizeof(BITMAP), &bm);
2098 dcb = CreateCompatibleDC(NULL);
2100 SelectObject(dcb, hbm);
2104 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
2105 * couldn't be loaded
2107 memset(&bm, 0, sizeof(bm));
2112 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
2113 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
2114 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL, NULL);
2116 ERR("Wine logo requested, but failed to create surface\n");
2121 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
2122 if(FAILED(hr)) goto out;
2123 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
2124 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
2126 colorkey.dwColorSpaceLowValue = 0;
2127 colorkey.dwColorSpaceHighValue = 0;
2128 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2130 /* Fill the surface with a white color to show that wined3d is there */
2131 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2144 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2146 /* Under DirectX you can have texture stage operations even if no texture is
2147 bound, whereas opengl will only do texture operations when a valid texture is
2148 bound. We emulate this by creating dummy textures and binding them to each
2149 texture stage, but disable all stages by default. Hence if a stage is enabled
2150 then the default texture will kick in until replaced by a SetTexture call */
2153 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2154 /* The dummy texture does not have client storage backing */
2155 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2156 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2158 for (i = 0; i < GL_LIMITS(textures); i++) {
2159 GLubyte white = 255;
2161 /* Make appropriate texture active */
2162 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2163 checkGLcall("glActiveTextureARB");
2165 /* Generate an opengl texture name */
2166 glGenTextures(1, &This->dummyTextureName[i]);
2167 checkGLcall("glGenTextures");
2168 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2170 /* Generate a dummy 2d texture (not using 1d because they cause many
2171 * DRI drivers fall back to sw) */
2172 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2173 checkGLcall("glBindTexture");
2175 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2176 checkGLcall("glTexImage2D");
2178 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2179 /* Reenable because if supported it is enabled by default */
2180 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2181 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2187 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
2188 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2190 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2191 IWineD3DSwapChainImpl *swapchain = NULL;
2196 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
2198 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2199 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2201 /* TODO: Test if OpenGL is compiled in and loaded */
2203 TRACE("(%p) : Creating stateblock\n", This);
2204 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2205 hr = IWineD3DDevice_CreateStateBlock(iface,
2207 (IWineD3DStateBlock **)&This->stateBlock,
2209 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2210 WARN("Failed to create stateblock\n");
2213 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2214 This->updateStateBlock = This->stateBlock;
2215 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2217 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2218 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2220 This->NumberOfPalettes = 1;
2221 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2222 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2223 ERR("Out of memory!\n");
2226 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2227 if(!This->palettes[0]) {
2228 ERR("Out of memory!\n");
2231 for (i = 0; i < 256; ++i) {
2232 This->palettes[0][i].peRed = 0xFF;
2233 This->palettes[0][i].peGreen = 0xFF;
2234 This->palettes[0][i].peBlue = 0xFF;
2235 This->palettes[0][i].peFlags = 0xFF;
2237 This->currentPalette = 0;
2239 /* Initialize the texture unit mapping to a 1:1 mapping */
2240 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2241 if (state < GL_LIMITS(fragment_samplers)) {
2242 This->texUnitMap[state] = state;
2243 This->rev_tex_unit_map[state] = state;
2245 This->texUnitMap[state] = -1;
2246 This->rev_tex_unit_map[state] = -1;
2250 /* Setup the implicit swapchain */
2251 TRACE("Creating implicit swapchain\n");
2252 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2253 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2256 WARN("Failed to create implicit swapchain\n");
2260 This->NumberOfSwapChains = 1;
2261 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2262 if(!This->swapchains) {
2263 ERR("Out of memory!\n");
2266 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2268 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2269 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2270 This->render_targets[0] = swapchain->backBuffer[0];
2271 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2274 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2275 This->render_targets[0] = swapchain->frontBuffer;
2276 This->lastActiveRenderTarget = swapchain->frontBuffer;
2278 IWineD3DSurface_AddRef(This->render_targets[0]);
2279 This->activeContext = swapchain->context[0];
2280 This->lastThread = GetCurrentThreadId();
2282 /* Depth Stencil support */
2283 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2284 if (NULL != This->stencilBufferTarget) {
2285 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2288 hr = This->shader_backend->shader_alloc_private(iface);
2290 TRACE("Shader private data couldn't be allocated\n");
2293 hr = This->frag_pipe->alloc_private(iface);
2295 TRACE("Fragment pipeline private data couldn't be allocated\n");
2298 hr = This->blitter->alloc_private(iface);
2300 TRACE("Blitter private data couldn't be allocated\n");
2304 /* Set up some starting GL setup */
2306 /* Setup all the devices defaults */
2307 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2308 create_dummy_textures(This);
2312 /* Initialize the current view state */
2313 This->view_ident = 1;
2314 This->contexts[0]->last_was_rhw = 0;
2315 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2316 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2318 switch(wined3d_settings.offscreen_rendering_mode) {
2321 This->offscreenBuffer = GL_BACK;
2324 case ORM_BACKBUFFER:
2326 if(This->activeContext->aux_buffers > 0) {
2327 TRACE("Using auxilliary buffer for offscreen rendering\n");
2328 This->offscreenBuffer = GL_AUX0;
2330 TRACE("Using back buffer for offscreen rendering\n");
2331 This->offscreenBuffer = GL_BACK;
2336 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2339 /* Clear the screen */
2340 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2341 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2344 This->d3d_initialized = TRUE;
2346 if(wined3d_settings.logo) {
2347 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2349 This->highest_dirty_ps_const = 0;
2350 This->highest_dirty_vs_const = 0;
2354 HeapFree(GetProcessHeap(), 0, This->render_targets);
2355 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2356 HeapFree(GetProcessHeap(), 0, This->swapchains);
2357 This->NumberOfSwapChains = 0;
2358 if(This->palettes) {
2359 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2360 HeapFree(GetProcessHeap(), 0, This->palettes);
2362 This->NumberOfPalettes = 0;
2364 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2366 if(This->stateBlock) {
2367 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2368 This->stateBlock = NULL;
2370 if (This->blit_priv) {
2371 This->blitter->free_private(iface);
2373 if (This->fragment_priv) {
2374 This->frag_pipe->free_private(iface);
2376 if (This->shader_priv) {
2377 This->shader_backend->shader_free_private(iface);
2382 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2383 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2386 IWineD3DSwapChainImpl *swapchain = NULL;
2389 /* Setup the implicit swapchain */
2390 TRACE("Creating implicit swapchain\n");
2391 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2392 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2395 WARN("Failed to create implicit swapchain\n");
2399 This->NumberOfSwapChains = 1;
2400 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2401 if(!This->swapchains) {
2402 ERR("Out of memory!\n");
2405 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2409 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2413 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2415 IWineD3DResource_UnLoad(resource);
2416 IWineD3DResource_Release(resource);
2420 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2421 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2424 TRACE("(%p)\n", This);
2426 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2428 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2429 * it was created. Thus make sure a context is active for the glDelete* calls
2431 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2433 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2435 /* Unload resources */
2436 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2438 TRACE("Deleting high order patches\n");
2439 for(i = 0; i < PATCHMAP_SIZE; i++) {
2440 struct list *e1, *e2;
2441 struct WineD3DRectPatch *patch;
2442 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2443 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2444 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2448 /* Delete the palette conversion shader if it is around */
2449 if(This->paletteConversionShader) {
2451 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2453 This->paletteConversionShader = 0;
2456 /* Delete the pbuffer context if there is any */
2457 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2459 /* Delete the mouse cursor texture */
2460 if(This->cursorTexture) {
2462 glDeleteTextures(1, &This->cursorTexture);
2464 This->cursorTexture = 0;
2467 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2468 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2470 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2471 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2474 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2475 * private data, it might contain opengl pointers
2477 if(This->depth_blt_texture) {
2479 glDeleteTextures(1, &This->depth_blt_texture);
2481 This->depth_blt_texture = 0;
2483 if (This->depth_blt_rb) {
2485 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2487 This->depth_blt_rb = 0;
2488 This->depth_blt_rb_w = 0;
2489 This->depth_blt_rb_h = 0;
2492 /* Release the update stateblock */
2493 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2494 if(This->updateStateBlock != This->stateBlock)
2495 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2497 This->updateStateBlock = NULL;
2499 { /* because were not doing proper internal refcounts releasing the primary state block
2500 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2501 to set this->stateBlock = NULL; first */
2502 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2503 This->stateBlock = NULL;
2505 /* Release the stateblock */
2506 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2507 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2511 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2512 This->blitter->free_private(iface);
2513 This->frag_pipe->free_private(iface);
2514 This->shader_backend->shader_free_private(iface);
2516 /* Release the buffers (with sanity checks)*/
2517 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2518 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2519 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2520 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2522 This->stencilBufferTarget = NULL;
2524 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2525 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2526 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2528 TRACE("Setting rendertarget to NULL\n");
2529 This->render_targets[0] = NULL;
2531 if (This->auto_depth_stencil_buffer) {
2532 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2533 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2535 This->auto_depth_stencil_buffer = NULL;
2538 for(i=0; i < This->NumberOfSwapChains; i++) {
2539 TRACE("Releasing the implicit swapchain %d\n", i);
2540 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2541 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2545 HeapFree(GetProcessHeap(), 0, This->swapchains);
2546 This->swapchains = NULL;
2547 This->NumberOfSwapChains = 0;
2549 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2550 HeapFree(GetProcessHeap(), 0, This->palettes);
2551 This->palettes = NULL;
2552 This->NumberOfPalettes = 0;
2554 HeapFree(GetProcessHeap(), 0, This->render_targets);
2555 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2556 This->render_targets = NULL;
2557 This->draw_buffers = NULL;
2559 This->d3d_initialized = FALSE;
2563 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2564 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2567 for(i=0; i < This->NumberOfSwapChains; i++) {
2568 TRACE("Releasing the implicit swapchain %d\n", i);
2569 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2570 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2574 HeapFree(GetProcessHeap(), 0, This->swapchains);
2575 This->swapchains = NULL;
2576 This->NumberOfSwapChains = 0;
2580 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2581 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2582 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2584 * There is no way to deactivate thread safety once it is enabled.
2586 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2587 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2589 /*For now just store the flag(needed in case of ddraw) */
2590 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2595 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2596 const WINED3DDISPLAYMODE* pMode) {
2598 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2600 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &GLINFO_LOCATION);
2603 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2605 /* Resize the screen even without a window:
2606 * The app could have unset it with SetCooperativeLevel, but not called
2607 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2608 * but we don't have any hwnd
2611 memset(&devmode, 0, sizeof(devmode));
2612 devmode.dmSize = sizeof(devmode);
2613 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2614 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2615 devmode.dmPelsWidth = pMode->Width;
2616 devmode.dmPelsHeight = pMode->Height;
2618 devmode.dmDisplayFrequency = pMode->RefreshRate;
2619 if (pMode->RefreshRate != 0) {
2620 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2623 /* Only change the mode if necessary */
2624 if( (This->ddraw_width == pMode->Width) &&
2625 (This->ddraw_height == pMode->Height) &&
2626 (This->ddraw_format == pMode->Format) &&
2627 (pMode->RefreshRate == 0) ) {
2631 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2632 if (ret != DISP_CHANGE_SUCCESSFUL) {
2633 if(devmode.dmDisplayFrequency != 0) {
2634 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2635 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2636 devmode.dmDisplayFrequency = 0;
2637 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2639 if(ret != DISP_CHANGE_SUCCESSFUL) {
2640 return WINED3DERR_NOTAVAILABLE;
2644 /* Store the new values */
2645 This->ddraw_width = pMode->Width;
2646 This->ddraw_height = pMode->Height;
2647 This->ddraw_format = pMode->Format;
2649 /* And finally clip mouse to our screen */
2650 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2651 ClipCursor(&clip_rc);
2656 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2658 *ppD3D= This->wineD3D;
2659 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2660 IWineD3D_AddRef(*ppD3D);
2664 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2665 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2667 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2668 (This->adapter->TextureRam/(1024*1024)),
2669 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2670 /* return simulated texture memory left */
2671 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2675 * Get / Set Stream Source
2677 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2678 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2681 IWineD3DBuffer *oldSrc;
2683 if (StreamNumber >= MAX_STREAMS) {
2684 WARN("Stream out of range %d\n", StreamNumber);
2685 return WINED3DERR_INVALIDCALL;
2686 } else if(OffsetInBytes & 0x3) {
2687 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2688 return WINED3DERR_INVALIDCALL;
2691 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2692 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2694 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2696 if(oldSrc == pStreamData &&
2697 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2698 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2699 TRACE("Application is setting the old values over, nothing to do\n");
2703 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2705 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2706 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2709 /* Handle recording of state blocks */
2710 if (This->isRecordingState) {
2711 TRACE("Recording... not performing anything\n");
2712 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2713 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2717 if (pStreamData != NULL) {
2718 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2719 IWineD3DBuffer_AddRef(pStreamData);
2721 if (oldSrc != NULL) {
2722 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2723 IWineD3DBuffer_Release(oldSrc);
2726 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2731 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2732 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2734 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2736 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2737 This->stateBlock->streamSource[StreamNumber],
2738 This->stateBlock->streamOffset[StreamNumber],
2739 This->stateBlock->streamStride[StreamNumber]);
2741 if (StreamNumber >= MAX_STREAMS) {
2742 WARN("Stream out of range %d\n", StreamNumber);
2743 return WINED3DERR_INVALIDCALL;
2745 *pStream = This->stateBlock->streamSource[StreamNumber];
2746 *pStride = This->stateBlock->streamStride[StreamNumber];
2748 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2751 if (*pStream != NULL) {
2752 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2757 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2758 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2759 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2760 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2762 /* Verify input at least in d3d9 this is invalid*/
2763 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2764 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2765 return WINED3DERR_INVALIDCALL;
2767 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2768 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2769 return WINED3DERR_INVALIDCALL;
2772 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2773 return WINED3DERR_INVALIDCALL;
2776 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2777 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2779 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2780 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2782 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2783 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2784 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2790 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2791 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2793 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2794 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2796 TRACE("(%p) : returning %d\n", This, *Divider);
2802 * Get / Set & Multiply Transform
2804 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2805 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2807 /* Most of this routine, comments included copied from ddraw tree initially: */
2808 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2810 /* Handle recording of state blocks */
2811 if (This->isRecordingState) {
2812 TRACE("Recording... not performing anything\n");
2813 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2814 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2819 * If the new matrix is the same as the current one,
2820 * we cut off any further processing. this seems to be a reasonable
2821 * optimization because as was noticed, some apps (warcraft3 for example)
2822 * tend towards setting the same matrix repeatedly for some reason.
2824 * From here on we assume that the new matrix is different, wherever it matters.
2826 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2827 TRACE("The app is setting the same matrix over again\n");
2830 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2834 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2835 where ViewMat = Camera space, WorldMat = world space.
2837 In OpenGL, camera and world space is combined into GL_MODELVIEW
2838 matrix. The Projection matrix stay projection matrix.
2841 /* Capture the times we can just ignore the change for now */
2842 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2843 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2844 /* Handled by the state manager */
2847 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2851 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2853 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2854 *pMatrix = This->stateBlock->transforms[State];
2858 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2859 const WINED3DMATRIX *mat = NULL;
2862 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2863 * below means it will be recorded in a state block change, but it
2864 * works regardless where it is recorded.
2865 * If this is found to be wrong, change to StateBlock.
2867 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2868 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2870 if (State <= HIGHEST_TRANSFORMSTATE)
2872 mat = &This->updateStateBlock->transforms[State];
2874 FIXME("Unhandled transform state!!\n");
2877 multiply_matrix(&temp, mat, pMatrix);
2879 /* Apply change via set transform - will reapply to eg. lights this way */
2880 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2886 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2887 you can reference any indexes you want as long as that number max are enabled at any
2888 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2889 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2890 but when recording, just build a chain pretty much of commands to be replayed. */
2892 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2894 PLIGHTINFOEL *object = NULL;
2895 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2898 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2899 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2901 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2905 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2906 return WINED3DERR_INVALIDCALL;
2909 switch(pLight->Type) {
2910 case WINED3DLIGHT_POINT:
2911 case WINED3DLIGHT_SPOT:
2912 case WINED3DLIGHT_PARALLELPOINT:
2913 case WINED3DLIGHT_GLSPOT:
2914 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2917 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2918 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2919 return WINED3DERR_INVALIDCALL;
2923 case WINED3DLIGHT_DIRECTIONAL:
2924 /* Ignores attenuation */
2928 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2929 return WINED3DERR_INVALIDCALL;
2932 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2933 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2934 if(object->OriginalIndex == Index) break;
2939 TRACE("Adding new light\n");
2940 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2942 ERR("Out of memory error when allocating a light\n");
2943 return E_OUTOFMEMORY;
2945 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2946 object->glIndex = -1;
2947 object->OriginalIndex = Index;
2948 object->changed = TRUE;
2951 /* Initialize the object */
2952 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,
2953 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2954 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2955 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2956 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2957 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2958 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2960 /* Save away the information */
2961 object->OriginalParms = *pLight;
2963 switch (pLight->Type) {
2964 case WINED3DLIGHT_POINT:
2966 object->lightPosn[0] = pLight->Position.x;
2967 object->lightPosn[1] = pLight->Position.y;
2968 object->lightPosn[2] = pLight->Position.z;
2969 object->lightPosn[3] = 1.0f;
2970 object->cutoff = 180.0f;
2974 case WINED3DLIGHT_DIRECTIONAL:
2976 object->lightPosn[0] = -pLight->Direction.x;
2977 object->lightPosn[1] = -pLight->Direction.y;
2978 object->lightPosn[2] = -pLight->Direction.z;
2979 object->lightPosn[3] = 0.0;
2980 object->exponent = 0.0f;
2981 object->cutoff = 180.0f;
2984 case WINED3DLIGHT_SPOT:
2986 object->lightPosn[0] = pLight->Position.x;
2987 object->lightPosn[1] = pLight->Position.y;
2988 object->lightPosn[2] = pLight->Position.z;
2989 object->lightPosn[3] = 1.0;
2992 object->lightDirn[0] = pLight->Direction.x;
2993 object->lightDirn[1] = pLight->Direction.y;
2994 object->lightDirn[2] = pLight->Direction.z;
2995 object->lightDirn[3] = 1.0;
2998 * opengl-ish and d3d-ish spot lights use too different models for the
2999 * light "intensity" as a function of the angle towards the main light direction,
3000 * so we only can approximate very roughly.
3001 * however spot lights are rather rarely used in games (if ever used at all).
3002 * furthermore if still used, probably nobody pays attention to such details.
3004 if (pLight->Falloff == 0) {
3005 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
3006 * falloff resp. exponent parameter as an exponent, so the spot light lighting
3007 * will always be 1.0 for both of them, and we don't have to care for the
3008 * rest of the rather complex calculation
3010 object->exponent = 0;
3012 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
3013 if (rho < 0.0001) rho = 0.0001f;
3014 object->exponent = -0.3/log(cos(rho/2));
3016 if (object->exponent > 128.0) {
3017 object->exponent = 128.0;
3019 object->cutoff = pLight->Phi*90/M_PI;
3025 FIXME("Unrecognized light type %d\n", pLight->Type);
3028 /* Update the live definitions if the light is currently assigned a glIndex */
3029 if (object->glIndex != -1 && !This->isRecordingState) {
3030 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
3035 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
3036 PLIGHTINFOEL *lightInfo = NULL;
3037 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3038 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
3040 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
3042 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3043 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3044 if(lightInfo->OriginalIndex == Index) break;
3048 if (lightInfo == NULL) {
3049 TRACE("Light information requested but light not defined\n");
3050 return WINED3DERR_INVALIDCALL;
3053 *pLight = lightInfo->OriginalParms;
3058 * Get / Set Light Enable
3059 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
3061 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
3062 PLIGHTINFOEL *lightInfo = NULL;
3063 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3064 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3066 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
3068 /* Tests show true = 128...not clear why */
3069 Enable = Enable? 128: 0;
3071 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3072 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3073 if(lightInfo->OriginalIndex == Index) break;
3076 TRACE("Found light: %p\n", lightInfo);
3078 /* Special case - enabling an undefined light creates one with a strict set of parms! */
3079 if (lightInfo == NULL) {
3081 TRACE("Light enabled requested but light not defined, so defining one!\n");
3082 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
3084 /* Search for it again! Should be fairly quick as near head of list */
3085 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3086 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3087 if(lightInfo->OriginalIndex == Index) break;
3090 if (lightInfo == NULL) {
3091 FIXME("Adding default lights has failed dismally\n");
3092 return WINED3DERR_INVALIDCALL;
3096 lightInfo->enabledChanged = TRUE;
3098 if(lightInfo->glIndex != -1) {
3099 if(!This->isRecordingState) {
3100 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
3103 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
3104 lightInfo->glIndex = -1;
3106 TRACE("Light already disabled, nothing to do\n");
3108 lightInfo->enabled = FALSE;
3110 lightInfo->enabled = TRUE;
3111 if (lightInfo->glIndex != -1) {
3113 TRACE("Nothing to do as light was enabled\n");
3116 /* Find a free gl light */
3117 for(i = 0; i < This->maxConcurrentLights; i++) {
3118 if(This->updateStateBlock->activeLights[i] == NULL) {
3119 This->updateStateBlock->activeLights[i] = lightInfo;
3120 lightInfo->glIndex = i;
3124 if(lightInfo->glIndex == -1) {
3125 /* Our tests show that Windows returns D3D_OK in this situation, even with
3126 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3127 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3128 * as well for those lights.
3130 * TODO: Test how this affects rendering
3132 WARN("Too many concurrently active lights\n");
3136 /* i == lightInfo->glIndex */
3137 if(!This->isRecordingState) {
3138 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3146 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3148 PLIGHTINFOEL *lightInfo = NULL;
3149 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3151 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3152 TRACE("(%p) : for idx(%d)\n", This, Index);
3154 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3155 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3156 if(lightInfo->OriginalIndex == Index) break;
3160 if (lightInfo == NULL) {
3161 TRACE("Light enabled state requested but light not defined\n");
3162 return WINED3DERR_INVALIDCALL;
3164 /* true is 128 according to SetLightEnable */
3165 *pEnable = lightInfo->enabled ? 128 : 0;
3170 * Get / Set Clip Planes
3172 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3173 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3174 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3176 /* Validate Index */
3177 if (Index >= GL_LIMITS(clipplanes)) {
3178 TRACE("Application has requested clipplane this device doesn't support\n");
3179 return WINED3DERR_INVALIDCALL;
3182 This->updateStateBlock->changed.clipplane |= 1 << Index;
3184 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3185 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3186 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3187 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3188 TRACE("Application is setting old values over, nothing to do\n");
3192 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3193 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3194 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3195 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3197 /* Handle recording of state blocks */
3198 if (This->isRecordingState) {
3199 TRACE("Recording... not performing anything\n");
3203 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3208 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3210 TRACE("(%p) : for idx %d\n", This, Index);
3212 /* Validate Index */
3213 if (Index >= GL_LIMITS(clipplanes)) {
3214 TRACE("Application has requested clipplane this device doesn't support\n");
3215 return WINED3DERR_INVALIDCALL;
3218 pPlane[0] = This->stateBlock->clipplane[Index][0];
3219 pPlane[1] = This->stateBlock->clipplane[Index][1];
3220 pPlane[2] = This->stateBlock->clipplane[Index][2];
3221 pPlane[3] = This->stateBlock->clipplane[Index][3];
3226 * Get / Set Clip Plane Status
3227 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3229 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3230 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3231 FIXME("(%p) : stub\n", This);
3232 if (NULL == pClipStatus) {
3233 return WINED3DERR_INVALIDCALL;
3235 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3236 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3240 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3242 FIXME("(%p) : stub\n", This);
3243 if (NULL == pClipStatus) {
3244 return WINED3DERR_INVALIDCALL;
3246 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3247 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3252 * Get / Set Material
3254 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3255 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3257 This->updateStateBlock->changed.material = TRUE;
3258 This->updateStateBlock->material = *pMaterial;
3260 /* Handle recording of state blocks */
3261 if (This->isRecordingState) {
3262 TRACE("Recording... not performing anything\n");
3266 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3270 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3271 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3272 *pMaterial = This->updateStateBlock->material;
3273 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3274 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3275 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3276 pMaterial->Ambient.b, pMaterial->Ambient.a);
3277 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3278 pMaterial->Specular.b, pMaterial->Specular.a);
3279 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3280 pMaterial->Emissive.b, pMaterial->Emissive.a);
3281 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3289 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DBuffer* pIndexData, WINED3DFORMAT fmt) {
3290 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3291 IWineD3DBuffer *oldIdxs;
3293 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3294 oldIdxs = This->updateStateBlock->pIndexData;
3296 This->updateStateBlock->changed.indices = TRUE;
3297 This->updateStateBlock->pIndexData = pIndexData;
3298 This->updateStateBlock->IndexFmt = fmt;
3300 /* Handle recording of state blocks */
3301 if (This->isRecordingState) {
3302 TRACE("Recording... not performing anything\n");
3303 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
3304 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
3308 if(oldIdxs != pIndexData) {
3309 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3311 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
3312 IWineD3DBuffer_AddRef(pIndexData);
3315 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
3316 IWineD3DBuffer_Release(oldIdxs);
3323 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DBuffer** ppIndexData) {
3324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3326 *ppIndexData = This->stateBlock->pIndexData;
3328 /* up ref count on ppindexdata */
3330 IWineD3DBuffer_AddRef(*ppIndexData);
3331 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3333 TRACE("(%p) No index data set\n", This);
3335 TRACE("Returning %p\n", *ppIndexData);
3340 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3341 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3342 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3343 TRACE("(%p)->(%d)\n", This, BaseIndex);
3345 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3346 TRACE("Application is setting the old value over, nothing to do\n");
3350 This->updateStateBlock->baseVertexIndex = BaseIndex;
3352 if (This->isRecordingState) {
3353 TRACE("Recording... not performing anything\n");
3356 /* The base vertex index affects the stream sources */
3357 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3361 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3362 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3363 TRACE("(%p) : base_index %p\n", This, base_index);
3365 *base_index = This->stateBlock->baseVertexIndex;
3367 TRACE("Returning %u\n", *base_index);
3373 * Get / Set Viewports
3375 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3376 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3378 TRACE("(%p)\n", This);
3379 This->updateStateBlock->changed.viewport = TRUE;
3380 This->updateStateBlock->viewport = *pViewport;
3382 /* Handle recording of state blocks */
3383 if (This->isRecordingState) {
3384 TRACE("Recording... not performing anything\n");
3388 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3389 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3391 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3396 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3397 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3398 TRACE("(%p)\n", This);
3399 *pViewport = This->stateBlock->viewport;
3404 * Get / Set Render States
3405 * TODO: Verify against dx9 definitions
3407 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3409 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3410 DWORD oldValue = This->stateBlock->renderState[State];
3412 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3414 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3415 This->updateStateBlock->renderState[State] = Value;
3417 /* Handle recording of state blocks */
3418 if (This->isRecordingState) {
3419 TRACE("Recording... not performing anything\n");
3423 /* Compared here and not before the assignment to allow proper stateblock recording */
3424 if(Value == oldValue) {
3425 TRACE("Application is setting the old value over, nothing to do\n");
3427 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3433 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3434 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3435 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3436 *pValue = This->stateBlock->renderState[State];
3441 * Get / Set Sampler States
3442 * TODO: Verify against dx9 definitions
3445 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3446 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3449 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3450 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3452 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3453 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3456 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3457 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3458 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3461 * SetSampler is designed to allow for more than the standard up to 8 textures
3462 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3463 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3465 * http://developer.nvidia.com/object/General_FAQ.html#t6
3467 * There are two new settings for GForce
3469 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3470 * and the texture one:
3471 * GL_MAX_TEXTURE_COORDS_ARB.
3472 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3475 oldValue = This->stateBlock->samplerState[Sampler][Type];
3476 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3477 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3479 /* Handle recording of state blocks */
3480 if (This->isRecordingState) {
3481 TRACE("Recording... not performing anything\n");
3485 if(oldValue == Value) {
3486 TRACE("Application is setting the old value over, nothing to do\n");
3490 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3495 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3496 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3498 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3499 This, Sampler, debug_d3dsamplerstate(Type), Type);
3501 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3502 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3505 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3506 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3507 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3509 *Value = This->stateBlock->samplerState[Sampler][Type];
3510 TRACE("(%p) : Returning %#x\n", This, *Value);
3515 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3518 This->updateStateBlock->changed.scissorRect = TRUE;
3519 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3520 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3523 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3525 if(This->isRecordingState) {
3526 TRACE("Recording... not performing anything\n");
3530 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3535 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3536 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3538 *pRect = This->updateStateBlock->scissorRect;
3539 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3543 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3544 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3545 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3547 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3549 This->updateStateBlock->vertexDecl = pDecl;
3550 This->updateStateBlock->changed.vertexDecl = TRUE;
3552 if (This->isRecordingState) {
3553 TRACE("Recording... not performing anything\n");
3555 } else if(pDecl == oldDecl) {
3556 /* Checked after the assignment to allow proper stateblock recording */
3557 TRACE("Application is setting the old declaration over, nothing to do\n");
3561 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3565 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3566 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3568 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3570 *ppDecl = This->stateBlock->vertexDecl;
3571 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3575 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3576 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3577 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3579 This->updateStateBlock->vertexShader = pShader;
3580 This->updateStateBlock->changed.vertexShader = TRUE;
3582 if (This->isRecordingState) {
3583 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3584 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3585 TRACE("Recording... not performing anything\n");
3587 } else if(oldShader == pShader) {
3588 /* Checked here to allow proper stateblock recording */
3589 TRACE("App is setting the old shader over, nothing to do\n");
3593 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3594 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3595 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3597 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3602 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3603 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3605 if (NULL == ppShader) {
3606 return WINED3DERR_INVALIDCALL;
3608 *ppShader = This->stateBlock->vertexShader;
3609 if( NULL != *ppShader)
3610 IWineD3DVertexShader_AddRef(*ppShader);
3612 TRACE("(%p) : returning %p\n", This, *ppShader);
3616 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3617 IWineD3DDevice *iface,
3619 CONST BOOL *srcData,
3622 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3623 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3625 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3626 iface, srcData, start, count);
3628 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3630 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3631 for (i = 0; i < cnt; i++)
3632 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3634 for (i = start; i < cnt + start; ++i) {
3635 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3638 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3643 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3644 IWineD3DDevice *iface,
3649 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3650 int cnt = min(count, MAX_CONST_B - start);
3652 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3653 iface, dstData, start, count);
3655 if (dstData == NULL || cnt < 0)
3656 return WINED3DERR_INVALIDCALL;
3658 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3662 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3663 IWineD3DDevice *iface,
3668 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3669 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3671 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3672 iface, srcData, start, count);
3674 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3676 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3677 for (i = 0; i < cnt; i++)
3678 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3679 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3681 for (i = start; i < cnt + start; ++i) {
3682 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3685 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3690 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3691 IWineD3DDevice *iface,
3696 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3697 int cnt = min(count, MAX_CONST_I - start);
3699 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3700 iface, dstData, start, count);
3702 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3703 return WINED3DERR_INVALIDCALL;
3705 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3709 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3710 IWineD3DDevice *iface,
3712 CONST float *srcData,
3715 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3718 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3719 iface, srcData, start, count);
3721 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3722 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3723 return WINED3DERR_INVALIDCALL;
3725 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3727 for (i = 0; i < count; i++)
3728 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3729 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3732 if (!This->isRecordingState)
3734 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3735 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3738 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3739 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3744 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3745 IWineD3DDevice *iface,
3750 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3751 int cnt = min(count, This->d3d_vshader_constantF - start);
3753 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3754 iface, dstData, start, count);
3756 if (dstData == NULL || cnt < 0)
3757 return WINED3DERR_INVALIDCALL;
3759 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3763 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3765 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3767 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3771 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3772 int i = This->rev_tex_unit_map[unit];
3773 int j = This->texUnitMap[stage];
3775 This->texUnitMap[stage] = unit;
3776 if (i != -1 && i != stage) {
3777 This->texUnitMap[i] = -1;
3780 This->rev_tex_unit_map[unit] = stage;
3781 if (j != -1 && j != unit) {
3782 This->rev_tex_unit_map[j] = -1;
3786 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3789 This->fixed_function_usage_map = 0;
3790 for (i = 0; i < MAX_TEXTURES; ++i) {
3791 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3792 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3793 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3794 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3795 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3796 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3797 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3798 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3800 if (color_op == WINED3DTOP_DISABLE) {
3801 /* Not used, and disable higher stages */
3805 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3806 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3807 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3808 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3809 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3810 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3811 This->fixed_function_usage_map |= (1 << i);
3814 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3815 This->fixed_function_usage_map |= (1 << (i + 1));
3820 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3821 unsigned int i, tex;
3824 device_update_fixed_function_usage_map(This);
3825 ffu_map = This->fixed_function_usage_map;
3827 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3828 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3829 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3831 if (!(ffu_map & 1)) continue;
3833 if (This->texUnitMap[i] != i) {
3834 device_map_stage(This, i, i);
3835 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3836 markTextureStagesDirty(This, i);
3842 /* Now work out the mapping */
3844 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3846 if (!(ffu_map & 1)) continue;
3848 if (This->texUnitMap[i] != tex) {
3849 device_map_stage(This, i, tex);
3850 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3851 markTextureStagesDirty(This, i);
3858 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3859 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3860 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3863 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3864 if (sampler_type[i] && This->texUnitMap[i] != i)
3866 device_map_stage(This, i, i);
3867 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3868 if (i < MAX_TEXTURES) {
3869 markTextureStagesDirty(This, i);
3875 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3876 const DWORD *vshader_sampler_tokens, int unit)
3878 int current_mapping = This->rev_tex_unit_map[unit];
3880 if (current_mapping == -1) {
3881 /* Not currently used */
3885 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3886 /* Used by a fragment sampler */
3888 if (!pshader_sampler_tokens) {
3889 /* No pixel shader, check fixed function */
3890 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3893 /* Pixel shader, check the shader's sampler map */
3894 return !pshader_sampler_tokens[current_mapping];
3897 /* Used by a vertex sampler */
3898 return !vshader_sampler_tokens[current_mapping];
3901 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3902 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3903 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3904 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3905 int start = GL_LIMITS(combined_samplers) - 1;
3909 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3911 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3912 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3913 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3916 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3917 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3918 if (vshader_sampler_type[i])
3920 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3922 /* Already mapped somewhere */
3926 while (start >= 0) {
3927 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3929 device_map_stage(This, vsampler_idx, start);
3930 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3942 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3943 BOOL vs = use_vs(This->stateBlock);
3944 BOOL ps = use_ps(This->stateBlock);
3947 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3948 * that would be really messy and require shader recompilation
3949 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3950 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3953 device_map_psamplers(This);
3955 device_map_fixed_function_samplers(This);
3959 device_map_vsamplers(This, ps);
3963 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3964 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3965 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3966 This->updateStateBlock->pixelShader = pShader;
3967 This->updateStateBlock->changed.pixelShader = TRUE;
3969 /* Handle recording of state blocks */
3970 if (This->isRecordingState) {
3971 TRACE("Recording... not performing anything\n");
3974 if (This->isRecordingState) {
3975 TRACE("Recording... not performing anything\n");
3976 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3977 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3981 if(pShader == oldShader) {
3982 TRACE("App is setting the old pixel shader over, nothing to do\n");
3986 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3987 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3989 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3990 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3995 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3998 if (NULL == ppShader) {
3999 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4000 return WINED3DERR_INVALIDCALL;
4003 *ppShader = This->stateBlock->pixelShader;
4004 if (NULL != *ppShader) {
4005 IWineD3DPixelShader_AddRef(*ppShader);
4007 TRACE("(%p) : returning %p\n", This, *ppShader);
4011 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4012 IWineD3DDevice *iface,
4014 CONST BOOL *srcData,
4017 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4018 unsigned int i, cnt = min(count, MAX_CONST_B - start);
4020 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
4021 iface, srcData, start, count);
4023 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
4025 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4026 for (i = 0; i < cnt; i++)
4027 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4029 for (i = start; i < cnt + start; ++i) {
4030 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
4033 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4038 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4039 IWineD3DDevice *iface,
4044 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4045 int cnt = min(count, MAX_CONST_B - start);
4047 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4048 iface, dstData, start, count);
4050 if (dstData == NULL || cnt < 0)
4051 return WINED3DERR_INVALIDCALL;
4053 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4057 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4058 IWineD3DDevice *iface,
4063 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4064 unsigned int i, cnt = min(count, MAX_CONST_I - start);
4066 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
4067 iface, srcData, start, count);
4069 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
4071 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4072 for (i = 0; i < cnt; i++)
4073 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4074 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4076 for (i = start; i < cnt + start; ++i) {
4077 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
4080 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4085 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4086 IWineD3DDevice *iface,
4091 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4092 int cnt = min(count, MAX_CONST_I - start);
4094 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4095 iface, dstData, start, count);
4097 if (dstData == NULL || cnt < 0)
4098 return WINED3DERR_INVALIDCALL;
4100 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4104 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4105 IWineD3DDevice *iface,
4107 CONST float *srcData,
4110 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4113 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4114 iface, srcData, start, count);
4116 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4117 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
4118 return WINED3DERR_INVALIDCALL;
4120 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4122 for (i = 0; i < count; i++)
4123 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4124 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4127 if (!This->isRecordingState)
4129 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
4130 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4133 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
4134 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
4139 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4140 IWineD3DDevice *iface,
4145 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4146 int cnt = min(count, This->d3d_pshader_constantF - start);
4148 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4149 iface, dstData, start, count);
4151 if (dstData == NULL || cnt < 0)
4152 return WINED3DERR_INVALIDCALL;
4154 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4158 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4159 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4160 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
4163 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4166 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4170 if (stream_info->elements[WINED3D_FFP_NORMAL].data)
4172 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4175 if (!stream_info->elements[WINED3D_FFP_POSITION].data)
4177 ERR("Source has no position mask\n");
4178 return WINED3DERR_INVALIDCALL;
4181 /* We might access VBOs from this code, so hold the lock */
4184 if (dest->resource.allocatedMemory == NULL) {
4185 buffer_get_sysmem(dest);
4188 /* Get a pointer into the destination vbo(create one if none exists) and
4189 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4191 if (!dest->buffer_object && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT))
4193 dest->flags |= WINED3D_BUFFER_CREATEBO;
4194 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
4197 if (dest->buffer_object)
4199 unsigned char extrabytes = 0;
4200 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4201 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4202 * this may write 4 extra bytes beyond the area that should be written
4204 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4205 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4206 if(!dest_conv_addr) {
4207 ERR("Out of memory\n");
4208 /* Continue without storing converted vertices */
4210 dest_conv = dest_conv_addr;
4214 * a) WINED3DRS_CLIPPING is enabled
4215 * b) WINED3DVOP_CLIP is passed
4217 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4218 static BOOL warned = FALSE;
4220 * The clipping code is not quite correct. Some things need
4221 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4222 * so disable clipping for now.
4223 * (The graphics in Half-Life are broken, and my processvertices
4224 * test crashes with IDirect3DDevice3)
4230 FIXME("Clipping is broken and disabled for now\n");
4232 } else doClip = FALSE;
4233 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4235 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4238 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4239 WINED3DTS_PROJECTION,
4241 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4242 WINED3DTS_WORLDMATRIX(0),
4245 TRACE("View mat:\n");
4246 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);
4247 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);
4248 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);
4249 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);
4251 TRACE("Proj mat:\n");
4252 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);
4253 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);
4254 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);
4255 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);
4257 TRACE("World mat:\n");
4258 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);
4259 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);
4260 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);
4261 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);
4263 /* Get the viewport */
4264 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4265 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4266 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4268 multiply_matrix(&mat,&view_mat,&world_mat);
4269 multiply_matrix(&mat,&proj_mat,&mat);
4271 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4273 for (i = 0; i < dwCount; i+= 1) {
4274 unsigned int tex_index;
4276 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4277 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4278 /* The position first */
4279 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
4280 const float *p = (const float *)(element->data + i * element->stride);
4282 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4284 /* Multiplication with world, view and projection matrix */
4285 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);
4286 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);
4287 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);
4288 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);
4290 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4292 /* WARNING: The following things are taken from d3d7 and were not yet checked
4293 * against d3d8 or d3d9!
4296 /* Clipping conditions: From msdn
4298 * A vertex is clipped if it does not match the following requirements
4302 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4304 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4305 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4310 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4311 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4314 /* "Normal" viewport transformation (not clipped)
4315 * 1) The values are divided by rhw
4316 * 2) The y axis is negative, so multiply it with -1
4317 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4318 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4319 * 4) Multiply x with Width/2 and add Width/2
4320 * 5) The same for the height
4321 * 6) Add the viewpoint X and Y to the 2D coordinates and
4322 * The minimum Z value to z
4323 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4325 * Well, basically it's simply a linear transformation into viewport
4337 z *= vp.MaxZ - vp.MinZ;
4339 x += vp.Width / 2 + vp.X;
4340 y += vp.Height / 2 + vp.Y;
4345 /* That vertex got clipped
4346 * Contrary to OpenGL it is not dropped completely, it just
4347 * undergoes a different calculation.
4349 TRACE("Vertex got clipped\n");
4356 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4357 * outside of the main vertex buffer memory. That needs some more
4362 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4365 ( (float *) dest_ptr)[0] = x;
4366 ( (float *) dest_ptr)[1] = y;
4367 ( (float *) dest_ptr)[2] = z;
4368 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4370 dest_ptr += 3 * sizeof(float);
4372 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4373 dest_ptr += sizeof(float);
4378 ( (float *) dest_conv)[0] = x * w;
4379 ( (float *) dest_conv)[1] = y * w;
4380 ( (float *) dest_conv)[2] = z * w;
4381 ( (float *) dest_conv)[3] = w;
4383 dest_conv += 3 * sizeof(float);
4385 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4386 dest_conv += sizeof(float);
4390 if (DestFVF & WINED3DFVF_PSIZE) {
4391 dest_ptr += sizeof(DWORD);
4392 if(dest_conv) dest_conv += sizeof(DWORD);
4394 if (DestFVF & WINED3DFVF_NORMAL) {
4395 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4396 const float *normal = (const float *)(element->data + i * element->stride);
4397 /* AFAIK this should go into the lighting information */
4398 FIXME("Didn't expect the destination to have a normal\n");
4399 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4401 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4405 if (DestFVF & WINED3DFVF_DIFFUSE) {
4406 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4407 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4409 static BOOL warned = FALSE;
4412 ERR("No diffuse color in source, but destination has one\n");
4416 *( (DWORD *) dest_ptr) = 0xffffffff;
4417 dest_ptr += sizeof(DWORD);
4420 *( (DWORD *) dest_conv) = 0xffffffff;
4421 dest_conv += sizeof(DWORD);
4425 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4427 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4428 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4429 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4430 dest_conv += sizeof(DWORD);
4435 if (DestFVF & WINED3DFVF_SPECULAR) {
4436 /* What's the color value in the feedback buffer? */
4437 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4438 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4440 static BOOL warned = FALSE;
4443 ERR("No specular color in source, but destination has one\n");
4447 *( (DWORD *) dest_ptr) = 0xFF000000;
4448 dest_ptr += sizeof(DWORD);
4451 *( (DWORD *) dest_conv) = 0xFF000000;
4452 dest_conv += sizeof(DWORD);
4456 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4458 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4459 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4460 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4461 dest_conv += sizeof(DWORD);
4466 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4467 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4468 const float *tex_coord = (const float *)(element->data + i * element->stride);
4470 ERR("No source texture, but destination requests one\n");
4471 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4472 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4475 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4477 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4484 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4485 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4486 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4487 dwCount * get_flexible_vertex_size(DestFVF),
4489 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4490 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4497 #undef copy_and_next
4499 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4500 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4503 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4504 struct wined3d_stream_info stream_info;
4505 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4506 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4509 ERR("Output vertex declaration not implemented yet\n");
4512 /* Need any context to write to the vbo. */
4513 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4515 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4516 * control the streamIsUP flag, thus restore it afterwards.
4518 This->stateBlock->streamIsUP = FALSE;
4519 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4520 This->stateBlock->streamIsUP = streamWasUP;
4522 if(vbo || SrcStartIndex) {
4524 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4525 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4527 * Also get the start index in, but only loop over all elements if there's something to add at all.
4529 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4531 struct wined3d_stream_info_element *e = &stream_info.elements[i];
4532 if (e->buffer_object)
4534 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
4535 e->buffer_object = 0;
4536 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
4538 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4539 vb->buffer_object = 0;
4542 if (e->data) e->data += e->stride * SrcStartIndex;
4546 return process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4547 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4551 * Get / Set Texture Stage States
4552 * TODO: Verify against dx9 definitions
4554 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4555 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4556 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4558 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4560 if (Stage >= MAX_TEXTURES) {
4561 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4565 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4566 This->updateStateBlock->textureState[Stage][Type] = Value;
4568 if (This->isRecordingState) {
4569 TRACE("Recording... not performing anything\n");
4573 /* Checked after the assignments to allow proper stateblock recording */
4574 if(oldValue == Value) {
4575 TRACE("App is setting the old value over, nothing to do\n");
4579 if(Stage > This->stateBlock->lowest_disabled_stage &&
4580 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4581 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4582 * Changes in other states are important on disabled stages too
4587 if(Type == WINED3DTSS_COLOROP) {
4590 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4591 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4592 * they have to be disabled
4594 * The current stage is dirtified below.
4596 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4597 TRACE("Additionally dirtifying stage %u\n", i);
4598 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4600 This->stateBlock->lowest_disabled_stage = Stage;
4601 TRACE("New lowest disabled: %u\n", Stage);
4602 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4603 /* Previously disabled stage enabled. Stages above it may need enabling
4604 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4605 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4607 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4610 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4611 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4614 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4615 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4617 This->stateBlock->lowest_disabled_stage = i;
4618 TRACE("New lowest disabled: %u\n", i);
4622 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4627 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4628 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4629 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4630 *pValue = This->updateStateBlock->textureState[Stage][Type];
4637 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4638 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4639 IWineD3DBaseTexture *oldTexture;
4641 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4643 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4644 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4647 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4648 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4649 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4652 oldTexture = This->updateStateBlock->textures[Stage];
4654 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4655 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
4657 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4658 return WINED3DERR_INVALIDCALL;
4661 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4662 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4664 This->updateStateBlock->changed.textures |= 1 << Stage;
4665 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4666 This->updateStateBlock->textures[Stage] = pTexture;
4668 /* Handle recording of state blocks */
4669 if (This->isRecordingState) {
4670 TRACE("Recording... not performing anything\n");
4674 if(oldTexture == pTexture) {
4675 TRACE("App is setting the same texture again, nothing to do\n");
4679 /** NOTE: MSDN says that setTexture increases the reference count,
4680 * and that the application must set the texture back to null (or have a leaky application),
4681 * This means we should pass the refcount up to the parent
4682 *******************************/
4683 if (NULL != This->updateStateBlock->textures[Stage]) {
4684 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4685 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4686 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4688 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4690 if (!oldTexture || dimensions != IWineD3DBaseTexture_GetTextureDimensions(oldTexture))
4692 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4695 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4696 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4697 * so the COLOROP and ALPHAOP have to be dirtified.
4699 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4700 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4702 if(bindCount == 1) {
4703 new->baseTexture.sampler = Stage;
4705 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4709 if (NULL != oldTexture) {
4710 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4711 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4713 IWineD3DBaseTexture_Release(oldTexture);
4714 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4715 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4716 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4719 if(bindCount && old->baseTexture.sampler == Stage) {
4721 /* Have to do a search for the other sampler(s) where the texture is bound to
4722 * Shouldn't happen as long as apps bind a texture only to one stage
4724 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4725 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4726 if(This->updateStateBlock->textures[i] == oldTexture) {
4727 old->baseTexture.sampler = i;
4734 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4739 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4740 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4742 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4744 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4745 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4748 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4749 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4750 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4753 *ppTexture=This->stateBlock->textures[Stage];
4755 IWineD3DBaseTexture_AddRef(*ppTexture);
4757 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4765 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4766 IWineD3DSurface **ppBackBuffer) {
4767 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4768 IWineD3DSwapChain *swapChain;
4771 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4773 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4774 if (hr == WINED3D_OK) {
4775 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4776 IWineD3DSwapChain_Release(swapChain);
4778 *ppBackBuffer = NULL;
4783 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4784 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4785 WARN("(%p) : stub, calling idirect3d for now\n", This);
4786 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4789 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4790 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4791 IWineD3DSwapChain *swapChain;
4794 if(iSwapChain > 0) {
4795 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4796 if (hr == WINED3D_OK) {
4797 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4798 IWineD3DSwapChain_Release(swapChain);
4800 FIXME("(%p) Error getting display mode\n", This);
4803 /* Don't read the real display mode,
4804 but return the stored mode instead. X11 can't change the color
4805 depth, and some apps are pretty angry if they SetDisplayMode from
4806 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4808 Also don't relay to the swapchain because with ddraw it's possible
4809 that there isn't a swapchain at all */
4810 pMode->Width = This->ddraw_width;
4811 pMode->Height = This->ddraw_height;
4812 pMode->Format = This->ddraw_format;
4813 pMode->RefreshRate = 0;
4821 * Stateblock related functions
4824 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4825 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4826 IWineD3DStateBlock *stateblock;
4829 TRACE("(%p)\n", This);
4831 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4833 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4834 if (FAILED(hr)) return hr;
4836 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4837 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4838 This->isRecordingState = TRUE;
4840 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4845 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4846 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4848 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4850 if (!This->isRecordingState) {
4851 WARN("(%p) not recording! returning error\n", This);
4852 *ppStateBlock = NULL;
4853 return WINED3DERR_INVALIDCALL;
4856 for (i = 0; i <= WINEHIGHEST_RENDER_STATE >> 5; ++i)
4858 DWORD map = object->changed.renderState[i];
4859 for (j = 0; map; map >>= 1, ++j)
4861 if (!(map & 1)) continue;
4863 object->contained_render_states[object->num_contained_render_states++] = (i << 5) | j;
4867 for (i = 0; i <= HIGHEST_TRANSFORMSTATE >> 5; ++i)
4869 DWORD map = object->changed.transform[i];
4870 for (j = 0; map; map >>= 1, ++j)
4872 if (!(map & 1)) continue;
4874 object->contained_transform_states[object->num_contained_transform_states++] = (i << 5) | j;
4877 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4878 if(object->changed.vertexShaderConstantsF[i]) {
4879 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4880 object->num_contained_vs_consts_f++;
4883 for(i = 0; i < MAX_CONST_I; i++) {
4884 if (object->changed.vertexShaderConstantsI & (1 << i))
4886 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4887 object->num_contained_vs_consts_i++;
4890 for(i = 0; i < MAX_CONST_B; i++) {
4891 if (object->changed.vertexShaderConstantsB & (1 << i))
4893 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4894 object->num_contained_vs_consts_b++;
4897 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
4899 if (object->changed.pixelShaderConstantsF[i])
4901 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
4902 ++object->num_contained_ps_consts_f;
4905 for(i = 0; i < MAX_CONST_I; i++) {
4906 if (object->changed.pixelShaderConstantsI & (1 << i))
4908 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4909 object->num_contained_ps_consts_i++;
4912 for(i = 0; i < MAX_CONST_B; i++) {
4913 if (object->changed.pixelShaderConstantsB & (1 << i))
4915 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4916 object->num_contained_ps_consts_b++;
4919 for(i = 0; i < MAX_TEXTURES; i++) {
4920 DWORD map = object->changed.textureState[i];
4922 for(j = 0; map; map >>= 1, ++j)
4924 if (!(map & 1)) continue;
4926 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4927 object->contained_tss_states[object->num_contained_tss_states].state = j;
4928 ++object->num_contained_tss_states;
4931 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4932 DWORD map = object->changed.samplerState[i];
4934 for (j = 0; map; map >>= 1, ++j)
4936 if (!(map & 1)) continue;
4938 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4939 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4940 ++object->num_contained_sampler_states;
4944 *ppStateBlock = (IWineD3DStateBlock*) object;
4945 This->isRecordingState = FALSE;
4946 This->updateStateBlock = This->stateBlock;
4947 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4948 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4949 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4954 * Scene related functions
4956 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4957 /* At the moment we have no need for any functionality at the beginning
4959 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4960 TRACE("(%p)\n", This);
4963 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4964 return WINED3DERR_INVALIDCALL;
4966 This->inScene = TRUE;
4970 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4971 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4972 TRACE("(%p)\n", This);
4974 if(!This->inScene) {
4975 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4976 return WINED3DERR_INVALIDCALL;
4979 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4980 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4982 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4986 This->inScene = FALSE;
4990 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4991 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4992 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4993 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4994 IWineD3DSwapChain *swapChain = NULL;
4996 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4998 TRACE("(%p) Presenting the frame\n", This);
5000 for(i = 0 ; i < swapchains ; i ++) {
5002 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
5003 TRACE("presentinng chain %d, %p\n", i, swapChain);
5004 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5005 IWineD3DSwapChain_Release(swapChain);
5011 /* Not called from the VTable (internal subroutine) */
5012 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
5013 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
5014 float Z, DWORD Stencil) {
5015 GLbitfield glMask = 0;
5017 WINED3DRECT curRect;
5019 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
5020 UINT drawable_width, drawable_height;
5021 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
5022 IWineD3DSwapChainImpl *swapchain = NULL;
5024 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5025 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5026 * for the cleared parts, and the untouched parts.
5028 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5029 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5030 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5031 * checking all this if the dest surface is in the drawable anyway.
5033 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5035 if(vp->X != 0 || vp->Y != 0 ||
5036 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5037 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5040 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5041 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5042 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5043 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5044 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5047 if(Count > 0 && pRects && (
5048 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5049 pRects[0].x2 < target->currentDesc.Width ||
5050 pRects[0].y2 < target->currentDesc.Height)) {
5051 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5058 target->get_drawable_size(target, &drawable_width, &drawable_height);
5060 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5063 /* Only set the values up once, as they are not changing */
5064 if (Flags & WINED3DCLEAR_STENCIL) {
5065 glClearStencil(Stencil);
5066 checkGLcall("glClearStencil");
5067 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5068 glStencilMask(0xFFFFFFFF);
5071 if (Flags & WINED3DCLEAR_ZBUFFER) {
5072 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5073 glDepthMask(GL_TRUE);
5075 checkGLcall("glClearDepth");
5076 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5077 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5079 if (vp->X != 0 || vp->Y != 0 ||
5080 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5081 surface_load_ds_location(This->stencilBufferTarget, location);
5083 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5084 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5085 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5086 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5087 surface_load_ds_location(This->stencilBufferTarget, location);
5089 else if (Count > 0 && pRects && (
5090 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5091 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5092 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5093 surface_load_ds_location(This->stencilBufferTarget, location);
5097 if (Flags & WINED3DCLEAR_TARGET) {
5098 TRACE("Clearing screen with glClear to color %x\n", Color);
5099 glClearColor(D3DCOLOR_R(Color),
5103 checkGLcall("glClearColor");
5105 /* Clear ALL colors! */
5106 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5107 glMask = glMask | GL_COLOR_BUFFER_BIT;
5110 vp_rect.left = vp->X;
5111 vp_rect.top = vp->Y;
5112 vp_rect.right = vp->X + vp->Width;
5113 vp_rect.bottom = vp->Y + vp->Height;
5114 if (!(Count > 0 && pRects)) {
5115 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5116 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5118 if(This->render_offscreen) {
5119 glScissor(vp_rect.left, vp_rect.top,
5120 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5122 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5123 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5125 checkGLcall("glScissor");
5127 checkGLcall("glClear");
5129 /* Now process each rect in turn */
5130 for (i = 0; i < Count; i++) {
5131 /* Note gl uses lower left, width/height */
5132 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5133 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5134 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5136 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5137 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5138 curRect.x1, (target->currentDesc.Height - curRect.y2),
5139 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5141 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5142 * The rectangle is not cleared, no error is returned, but further rectanlges are
5143 * still cleared if they are valid
5145 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5146 TRACE("Rectangle with negative dimensions, ignoring\n");
5150 if(This->render_offscreen) {
5151 glScissor(curRect.x1, curRect.y1,
5152 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5154 glScissor(curRect.x1, drawable_height - curRect.y2,
5155 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5157 checkGLcall("glScissor");
5160 checkGLcall("glClear");
5164 /* Restore the old values (why..?) */
5165 if (Flags & WINED3DCLEAR_STENCIL) {
5166 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5168 if (Flags & WINED3DCLEAR_TARGET) {
5169 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5170 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5171 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5172 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5173 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5175 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5176 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5178 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5180 if (Flags & WINED3DCLEAR_ZBUFFER) {
5181 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5182 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5183 surface_modify_ds_location(This->stencilBufferTarget, location);
5188 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5189 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5192 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5198 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5199 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5200 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5201 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5203 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5204 Count, pRects, Flags, Color, Z, Stencil);
5206 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5207 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5208 /* TODO: What about depth stencil buffers without stencil bits? */
5209 return WINED3DERR_INVALIDCALL;
5212 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5219 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
5220 WINED3DPRIMITIVETYPE primitive_type)
5222 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5224 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
5226 This->updateStateBlock->changed.primitive_type = TRUE;
5227 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
5230 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
5231 WINED3DPRIMITIVETYPE *primitive_type)
5233 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5235 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
5237 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
5239 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
5242 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
5244 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5246 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
5248 if(!This->stateBlock->vertexDecl) {
5249 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5250 return WINED3DERR_INVALIDCALL;
5253 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5254 if(This->stateBlock->streamIsUP) {
5255 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5256 This->stateBlock->streamIsUP = FALSE;
5259 if(This->stateBlock->loadBaseVertexIndex != 0) {
5260 This->stateBlock->loadBaseVertexIndex = 0;
5261 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5263 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5264 drawPrimitive(iface, vertex_count, 0/* NumVertices */, StartVertex /* start_idx */,
5265 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5269 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5270 UINT minIndex, UINT NumVertices, UINT startIndex, UINT index_count)
5272 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5274 IWineD3DBuffer *pIB;
5277 pIB = This->stateBlock->pIndexData;
5279 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5280 * without an index buffer set. (The first time at least...)
5281 * D3D8 simply dies, but I doubt it can do much harm to return
5282 * D3DERR_INVALIDCALL there as well. */
5283 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5284 return WINED3DERR_INVALIDCALL;
5287 if(!This->stateBlock->vertexDecl) {
5288 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5289 return WINED3DERR_INVALIDCALL;
5292 if(This->stateBlock->streamIsUP) {
5293 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5294 This->stateBlock->streamIsUP = FALSE;
5296 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
5298 TRACE("(%p) : min %u, vertex count %u, startIdx %u, index count %u\n",
5299 This, minIndex, NumVertices, startIndex, index_count);
5301 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
5307 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5308 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5309 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5312 drawPrimitive(iface, index_count, NumVertices, startIndex, idxStride,
5313 vbo ? NULL : ((struct wined3d_buffer *) pIB)->resource.allocatedMemory, minIndex);
5318 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
5319 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5321 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5324 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
5325 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
5327 if(!This->stateBlock->vertexDecl) {
5328 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5329 return WINED3DERR_INVALIDCALL;
5332 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5333 vb = This->stateBlock->streamSource[0];
5334 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5335 if (vb) IWineD3DBuffer_Release(vb);
5336 This->stateBlock->streamOffset[0] = 0;
5337 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5338 This->stateBlock->streamIsUP = TRUE;
5339 This->stateBlock->loadBaseVertexIndex = 0;
5341 /* TODO: Only mark dirty if drawing from a different UP address */
5342 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5344 drawPrimitive(iface, vertex_count, 0 /* NumVertices */, 0 /* start_idx */,
5345 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5347 /* MSDN specifies stream zero settings must be set to NULL */
5348 This->stateBlock->streamStride[0] = 0;
5349 This->stateBlock->streamSource[0] = NULL;
5351 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5352 * the new stream sources or use UP drawing again
5357 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, UINT MinVertexIndex,
5358 UINT NumVertices, UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
5359 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5362 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5366 TRACE("(%p) : MinVtxIdx %u, NumVIdx %u, index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u\n",
5367 This, MinVertexIndex, NumVertices, index_count, pIndexData,
5368 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5370 if(!This->stateBlock->vertexDecl) {
5371 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5372 return WINED3DERR_INVALIDCALL;
5375 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
5381 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5382 vb = This->stateBlock->streamSource[0];
5383 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5384 if (vb) IWineD3DBuffer_Release(vb);
5385 This->stateBlock->streamIsUP = TRUE;
5386 This->stateBlock->streamOffset[0] = 0;
5387 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5389 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5390 This->stateBlock->baseVertexIndex = 0;
5391 This->stateBlock->loadBaseVertexIndex = 0;
5392 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5393 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5394 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5396 drawPrimitive(iface, index_count, NumVertices, 0 /* start_idx */,
5397 idxStride, pIndexData, MinVertexIndex);
5399 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5400 This->stateBlock->streamSource[0] = NULL;
5401 This->stateBlock->streamStride[0] = 0;
5402 ib = This->stateBlock->pIndexData;
5404 IWineD3DBuffer_Release(ib);
5405 This->stateBlock->pIndexData = NULL;
5407 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5408 * SetStreamSource to specify a vertex buffer
5414 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5415 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
5417 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5419 /* Mark the state dirty until we have nicer tracking
5420 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5423 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5424 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5425 This->stateBlock->baseVertexIndex = 0;
5426 This->up_strided = DrawPrimStrideData;
5427 drawPrimitive(iface, vertex_count, 0, 0, 0, NULL, 0);
5428 This->up_strided = NULL;
5432 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5433 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
5434 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
5436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5437 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5439 /* Mark the state dirty until we have nicer tracking
5440 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5443 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5444 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5445 This->stateBlock->streamIsUP = TRUE;
5446 This->stateBlock->baseVertexIndex = 0;
5447 This->up_strided = DrawPrimStrideData;
5448 drawPrimitive(iface, vertex_count, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData, 0 /* minindex */);
5449 This->up_strided = NULL;
5453 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5454 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5455 * not callable by the app directly no parameter validation checks are needed here.
5457 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5458 WINED3DLOCKED_BOX src;
5459 WINED3DLOCKED_BOX dst;
5461 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5463 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5464 * dirtification to improve loading performance.
5466 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5467 if(FAILED(hr)) return hr;
5468 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5470 IWineD3DVolume_UnlockBox(pSourceVolume);
5474 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5476 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5478 IWineD3DVolume_UnlockBox(pSourceVolume);
5480 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5485 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5486 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5487 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5488 HRESULT hr = WINED3D_OK;
5489 WINED3DRESOURCETYPE sourceType;
5490 WINED3DRESOURCETYPE destinationType;
5493 /* TODO: think about moving the code into IWineD3DBaseTexture */
5495 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5497 /* verify that the source and destination textures aren't NULL */
5498 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5499 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5500 This, pSourceTexture, pDestinationTexture);
5501 hr = WINED3DERR_INVALIDCALL;
5504 if (pSourceTexture == pDestinationTexture) {
5505 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5506 This, pSourceTexture, pDestinationTexture);
5507 hr = WINED3DERR_INVALIDCALL;
5509 /* Verify that the source and destination textures are the same type */
5510 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5511 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5513 if (sourceType != destinationType) {
5514 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5516 hr = WINED3DERR_INVALIDCALL;
5519 /* check that both textures have the identical numbers of levels */
5520 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5521 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5522 hr = WINED3DERR_INVALIDCALL;
5525 if (WINED3D_OK == hr) {
5526 IWineD3DBaseTextureImpl *pDestImpl = (IWineD3DBaseTextureImpl *) pDestinationTexture;
5528 /* Make sure that the destination texture is loaded */
5529 pDestImpl->baseTexture.internal_preload(pDestinationTexture, SRGB_RGB);
5531 /* Update every surface level of the texture */
5532 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5534 switch (sourceType) {
5535 case WINED3DRTYPE_TEXTURE:
5537 IWineD3DSurface *srcSurface;
5538 IWineD3DSurface *destSurface;
5540 for (i = 0 ; i < levels ; ++i) {
5541 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5542 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5543 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5544 IWineD3DSurface_Release(srcSurface);
5545 IWineD3DSurface_Release(destSurface);
5546 if (WINED3D_OK != hr) {
5547 WARN("(%p) : Call to update surface failed\n", This);
5553 case WINED3DRTYPE_CUBETEXTURE:
5555 IWineD3DSurface *srcSurface;
5556 IWineD3DSurface *destSurface;
5557 WINED3DCUBEMAP_FACES faceType;
5559 for (i = 0 ; i < levels ; ++i) {
5560 /* Update each cube face */
5561 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5562 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5563 if (WINED3D_OK != hr) {
5564 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5566 TRACE("Got srcSurface %p\n", srcSurface);
5568 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5569 if (WINED3D_OK != hr) {
5570 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5572 TRACE("Got desrSurface %p\n", destSurface);
5574 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5575 IWineD3DSurface_Release(srcSurface);
5576 IWineD3DSurface_Release(destSurface);
5577 if (WINED3D_OK != hr) {
5578 WARN("(%p) : Call to update surface failed\n", This);
5586 case WINED3DRTYPE_VOLUMETEXTURE:
5588 IWineD3DVolume *srcVolume = NULL;
5589 IWineD3DVolume *destVolume = NULL;
5591 for (i = 0 ; i < levels ; ++i) {
5592 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5593 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5594 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5595 IWineD3DVolume_Release(srcVolume);
5596 IWineD3DVolume_Release(destVolume);
5597 if (WINED3D_OK != hr) {
5598 WARN("(%p) : Call to update volume failed\n", This);
5606 FIXME("(%p) : Unsupported source and destination type\n", This);
5607 hr = WINED3DERR_INVALIDCALL;
5614 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5615 IWineD3DSwapChain *swapChain;
5617 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5618 if(hr == WINED3D_OK) {
5619 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5620 IWineD3DSwapChain_Release(swapChain);
5625 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5626 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5627 IWineD3DBaseTextureImpl *texture;
5630 TRACE("(%p) : %p\n", This, pNumPasses);
5632 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5633 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5634 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5635 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5637 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5638 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5639 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5642 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5643 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5645 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5646 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5649 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5650 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5653 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5654 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5655 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5660 /* return a sensible default */
5663 TRACE("returning D3D_OK\n");
5667 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5671 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5672 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5673 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8
5674 || texture->resource.format_desc->format == WINED3DFMT_A8P8))
5676 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5681 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5682 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5685 PALETTEENTRY **palettes;
5687 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5689 if (PaletteNumber >= MAX_PALETTES) {
5690 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5691 return WINED3DERR_INVALIDCALL;
5694 if (PaletteNumber >= This->NumberOfPalettes) {
5695 NewSize = This->NumberOfPalettes;
5698 } while(PaletteNumber >= NewSize);
5699 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5701 ERR("Out of memory!\n");
5702 return E_OUTOFMEMORY;
5704 This->palettes = palettes;
5705 This->NumberOfPalettes = NewSize;
5708 if (!This->palettes[PaletteNumber]) {
5709 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5710 if (!This->palettes[PaletteNumber]) {
5711 ERR("Out of memory!\n");
5712 return E_OUTOFMEMORY;
5716 for (j = 0; j < 256; ++j) {
5717 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5718 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5719 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5720 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5722 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5723 TRACE("(%p) : returning\n", This);
5727 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5728 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5730 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5731 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5732 /* What happens in such situation isn't documented; Native seems to silently abort
5733 on such conditions. Return Invalid Call. */
5734 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5735 return WINED3DERR_INVALIDCALL;
5737 for (j = 0; j < 256; ++j) {
5738 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5739 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5740 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5741 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5743 TRACE("(%p) : returning\n", This);
5747 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5748 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5749 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5750 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5751 (tested with reference rasterizer). Return Invalid Call. */
5752 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5753 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5754 return WINED3DERR_INVALIDCALL;
5756 /*TODO: stateblocks */
5757 if (This->currentPalette != PaletteNumber) {
5758 This->currentPalette = PaletteNumber;
5759 dirtify_p8_texture_samplers(This);
5761 TRACE("(%p) : returning\n", This);
5765 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5766 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5767 if (PaletteNumber == NULL) {
5768 WARN("(%p) : returning Invalid Call\n", This);
5769 return WINED3DERR_INVALIDCALL;
5771 /*TODO: stateblocks */
5772 *PaletteNumber = This->currentPalette;
5773 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5777 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5778 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5782 FIXME("(%p) : stub\n", This);
5786 This->softwareVertexProcessing = bSoftware;
5791 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5792 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5796 FIXME("(%p) : stub\n", This);
5799 return This->softwareVertexProcessing;
5803 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5804 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5805 IWineD3DSwapChain *swapChain;
5808 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5810 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5811 if(hr == WINED3D_OK){
5812 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5813 IWineD3DSwapChain_Release(swapChain);
5815 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5821 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5822 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5824 if(nSegments != 0.0f) {
5827 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5834 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5835 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5839 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5845 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5846 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5847 /** TODO: remove casts to IWineD3DSurfaceImpl
5848 * NOTE: move code to surface to accomplish this
5849 ****************************************/
5850 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5851 int srcWidth, srcHeight;
5852 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5853 WINED3DFORMAT destFormat, srcFormat;
5855 int srcLeft, destLeft, destTop;
5856 WINED3DPOOL srcPool, destPool;
5858 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5859 glDescriptor *glDescription = NULL;
5860 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
5864 CONVERT_TYPES convert = NO_CONVERSION;
5866 WINED3DSURFACE_DESC winedesc;
5868 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5869 memset(&winedesc, 0, sizeof(winedesc));
5870 winedesc.Width = &srcSurfaceWidth;
5871 winedesc.Height = &srcSurfaceHeight;
5872 winedesc.Pool = &srcPool;
5873 winedesc.Format = &srcFormat;
5875 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5877 winedesc.Width = &destSurfaceWidth;
5878 winedesc.Height = &destSurfaceHeight;
5879 winedesc.Pool = &destPool;
5880 winedesc.Format = &destFormat;
5881 winedesc.Size = &destSize;
5883 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5885 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5886 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5887 return WINED3DERR_INVALIDCALL;
5890 /* This call loads the opengl surface directly, instead of copying the surface to the
5891 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5892 * copy in sysmem and use regular surface loading.
5894 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5895 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5896 if(convert != NO_CONVERSION) {
5897 return IWineD3DSurface_BltFast(pDestinationSurface,
5898 pDestPoint ? pDestPoint->x : 0,
5899 pDestPoint ? pDestPoint->y : 0,
5900 pSourceSurface, pSourceRect, 0);
5903 if (destFormat == WINED3DFMT_UNKNOWN) {
5904 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5905 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5907 /* Get the update surface description */
5908 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5911 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5914 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5915 checkGLcall("glActiveTextureARB");
5918 /* Make sure the surface is loaded and up to date */
5919 surface_internal_preload(pDestinationSurface, SRGB_RGB);
5920 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5922 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5924 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
5925 dst_format_desc = ((IWineD3DSurfaceImpl *)pDestinationSurface)->resource.format_desc;
5927 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5928 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5929 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5930 srcLeft = pSourceRect ? pSourceRect->left : 0;
5931 destLeft = pDestPoint ? pDestPoint->x : 0;
5932 destTop = pDestPoint ? pDestPoint->y : 0;
5935 /* This function doesn't support compressed textures
5936 the pitch is just bytesPerPixel * width */
5937 if(srcWidth != srcSurfaceWidth || srcLeft ){
5938 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
5939 offset += srcLeft * src_format_desc->byte_count;
5940 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5942 /* TODO DXT formats */
5944 if(pSourceRect != NULL && pSourceRect->top != 0){
5945 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
5947 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5948 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
5949 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5952 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5954 /* need to lock the surface to get the data */
5955 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5960 /* TODO: Cube and volume support */
5962 /* not a whole row so we have to do it a line at a time */
5965 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5966 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5968 for (j = destTop; j < (srcHeight + destTop); ++j)
5970 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, j,
5971 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
5975 } else { /* Full width, so just write out the whole texture */
5976 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5978 if (dst_format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
5980 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth)
5982 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across. */
5983 FIXME("Updating part of a compressed texture is not supported.\n");
5985 if (destFormat != srcFormat)
5987 FIXME("Updating mixed format compressed textures is not supported.\n");
5991 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
5992 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
5997 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
5998 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
6001 checkGLcall("glTexSubImage2D");
6005 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
6006 sampler = This->rev_tex_unit_map[0];
6007 if (sampler != -1) {
6008 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6014 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6016 struct WineD3DRectPatch *patch;
6017 GLenum old_primitive_type;
6021 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6023 if(!(Handle || pRectPatchInfo)) {
6024 /* TODO: Write a test for the return value, thus the FIXME */
6025 FIXME("Both Handle and pRectPatchInfo are NULL\n");
6026 return WINED3DERR_INVALIDCALL;
6030 i = PATCHMAP_HASHFUNC(Handle);
6032 LIST_FOR_EACH(e, &This->patches[i]) {
6033 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6034 if(patch->Handle == Handle) {
6041 TRACE("Patch does not exist. Creating a new one\n");
6042 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6043 patch->Handle = Handle;
6044 list_add_head(&This->patches[i], &patch->entry);
6046 TRACE("Found existing patch %p\n", patch);
6049 /* Since opengl does not load tesselated vertex attributes into numbered vertex
6050 * attributes we have to tesselate, read back, and draw. This needs a patch
6051 * management structure instance. Create one.
6053 * A possible improvement is to check if a vertex shader is used, and if not directly
6056 FIXME("Drawing an uncached patch. This is slow\n");
6057 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6060 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
6061 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
6062 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
6064 TRACE("Tesselation density or patch info changed, retesselating\n");
6066 if(pRectPatchInfo) {
6067 patch->RectPatchInfo = *pRectPatchInfo;
6069 patch->numSegs[0] = pNumSegs[0];
6070 patch->numSegs[1] = pNumSegs[1];
6071 patch->numSegs[2] = pNumSegs[2];
6072 patch->numSegs[3] = pNumSegs[3];
6074 hr = tesselate_rectpatch(This, patch);
6076 WARN("Patch tesselation failed\n");
6078 /* Do not release the handle to store the params of the patch */
6080 HeapFree(GetProcessHeap(), 0, patch);
6086 This->currentPatch = patch;
6087 old_primitive_type = This->stateBlock->gl_primitive_type;
6088 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
6089 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
6090 This->stateBlock->gl_primitive_type = old_primitive_type;
6091 This->currentPatch = NULL;
6093 /* Destroy uncached patches */
6095 HeapFree(GetProcessHeap(), 0, patch->mem);
6096 HeapFree(GetProcessHeap(), 0, patch);
6101 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6102 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6103 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6104 FIXME("(%p) : Stub\n", This);
6108 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6109 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6111 struct WineD3DRectPatch *patch;
6113 TRACE("(%p) Handle(%d)\n", This, Handle);
6115 i = PATCHMAP_HASHFUNC(Handle);
6116 LIST_FOR_EACH(e, &This->patches[i]) {
6117 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6118 if(patch->Handle == Handle) {
6119 TRACE("Deleting patch %p\n", patch);
6120 list_remove(&patch->entry);
6121 HeapFree(GetProcessHeap(), 0, patch->mem);
6122 HeapFree(GetProcessHeap(), 0, patch);
6127 /* TODO: Write a test for the return value */
6128 FIXME("Attempt to destroy nonexistent patch\n");
6129 return WINED3DERR_INVALIDCALL;
6132 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6134 IWineD3DSwapChain *swapchain;
6136 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6137 if (SUCCEEDED(hr)) {
6138 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6145 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
6146 const WINED3DRECT *rect, const float color[4])
6148 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6149 IWineD3DSwapChain *swapchain;
6151 swapchain = get_swapchain(surface);
6155 TRACE("Surface %p is onscreen\n", surface);
6157 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6159 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6160 buffer = surface_get_gl_buffer(surface, swapchain);
6161 glDrawBuffer(buffer);
6162 checkGLcall("glDrawBuffer()");
6164 TRACE("Surface %p is offscreen\n", surface);
6166 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6168 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6169 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6170 context_attach_depth_stencil_fbo(This, GL_FRAMEBUFFER_EXT, NULL, FALSE);
6174 glEnable(GL_SCISSOR_TEST);
6176 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6178 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6179 rect->x2 - rect->x1, rect->y2 - rect->y1);
6181 checkGLcall("glScissor");
6182 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6184 glDisable(GL_SCISSOR_TEST);
6186 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6188 glDisable(GL_BLEND);
6189 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6191 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6192 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6194 glClearColor(color[0], color[1], color[2], color[3]);
6195 glClear(GL_COLOR_BUFFER_BIT);
6196 checkGLcall("glClear");
6198 if (This->activeContext->current_fbo) {
6199 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6201 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6202 checkGLcall("glBindFramebuffer()");
6205 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6206 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6207 glDrawBuffer(GL_BACK);
6208 checkGLcall("glDrawBuffer()");
6214 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6215 unsigned int r, g, b, a;
6218 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6219 destfmt == WINED3DFMT_R8G8B8)
6222 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6224 a = (color & 0xff000000) >> 24;
6225 r = (color & 0x00ff0000) >> 16;
6226 g = (color & 0x0000ff00) >> 8;
6227 b = (color & 0x000000ff) >> 0;
6231 case WINED3DFMT_R5G6B5:
6232 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6239 TRACE("Returning %08x\n", ret);
6242 case WINED3DFMT_X1R5G5B5:
6243 case WINED3DFMT_A1R5G5B5:
6252 TRACE("Returning %08x\n", ret);
6255 case WINED3DFMT_A8_UNORM:
6256 TRACE("Returning %08x\n", a);
6259 case WINED3DFMT_X4R4G4B4:
6260 case WINED3DFMT_A4R4G4B4:
6269 TRACE("Returning %08x\n", ret);
6272 case WINED3DFMT_R3G3B2:
6279 TRACE("Returning %08x\n", ret);
6282 case WINED3DFMT_X8B8G8R8:
6283 case WINED3DFMT_R8G8B8A8_UNORM:
6288 TRACE("Returning %08x\n", ret);
6291 case WINED3DFMT_A2R10G10B10:
6293 r = (r * 1024) / 256;
6294 g = (g * 1024) / 256;
6295 b = (b * 1024) / 256;
6300 TRACE("Returning %08x\n", ret);
6303 case WINED3DFMT_R10G10B10A2_UNORM:
6305 r = (r * 1024) / 256;
6306 g = (g * 1024) / 256;
6307 b = (b * 1024) / 256;
6312 TRACE("Returning %08x\n", ret);
6316 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6321 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6323 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6325 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6327 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6328 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6329 return WINED3DERR_INVALIDCALL;
6332 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6333 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
6334 color_fill_fbo(iface, pSurface, pRect, c);
6337 /* Just forward this to the DirectDraw blitting engine */
6338 memset(&BltFx, 0, sizeof(BltFx));
6339 BltFx.dwSize = sizeof(BltFx);
6340 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
6341 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6342 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6346 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
6347 IWineD3DRendertargetView *rendertarget_view, const float color[4])
6349 IWineD3DResource *resource;
6350 IWineD3DSurface *surface;
6353 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
6356 ERR("Failed to get resource, hr %#x\n", hr);
6360 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
6362 FIXME("Only supported on surface resources\n");
6363 IWineD3DResource_Release(resource);
6367 surface = (IWineD3DSurface *)resource;
6369 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6371 color_fill_fbo(iface, surface, NULL, color);
6378 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
6380 c = ((DWORD)(color[2] * 255.0));
6381 c |= ((DWORD)(color[1] * 255.0)) << 8;
6382 c |= ((DWORD)(color[0] * 255.0)) << 16;
6383 c |= ((DWORD)(color[3] * 255.0)) << 24;
6385 /* Just forward this to the DirectDraw blitting engine */
6386 memset(&BltFx, 0, sizeof(BltFx));
6387 BltFx.dwSize = sizeof(BltFx);
6388 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
6389 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6392 ERR("Blt failed, hr %#x\n", hr);
6396 IWineD3DResource_Release(resource);
6399 /* rendertarget and depth stencil functions */
6400 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6401 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6403 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6404 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6405 return WINED3DERR_INVALIDCALL;
6408 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6409 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6410 /* Note inc ref on returned surface */
6411 if(*ppRenderTarget != NULL)
6412 IWineD3DSurface_AddRef(*ppRenderTarget);
6416 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6417 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6418 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6419 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6420 IWineD3DSwapChainImpl *Swapchain;
6423 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6425 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6426 if(hr != WINED3D_OK) {
6427 ERR("Can't get the swapchain\n");
6431 /* Make sure to release the swapchain */
6432 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6434 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6435 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6436 return WINED3DERR_INVALIDCALL;
6438 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6439 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6440 return WINED3DERR_INVALIDCALL;
6443 if(Swapchain->frontBuffer != Front) {
6444 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6446 if(Swapchain->frontBuffer)
6448 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6449 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
6451 Swapchain->frontBuffer = Front;
6453 if(Swapchain->frontBuffer) {
6454 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6455 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
6459 if(Back && !Swapchain->backBuffer) {
6460 /* We need memory for the back buffer array - only one back buffer this way */
6461 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6462 if(!Swapchain->backBuffer) {
6463 ERR("Out of memory\n");
6464 return E_OUTOFMEMORY;
6468 if(Swapchain->backBuffer[0] != Back) {
6469 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6471 /* What to do about the context here in the case of multithreading? Not sure.
6472 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6475 if(!Swapchain->backBuffer[0]) {
6476 /* GL was told to draw to the front buffer at creation,
6479 glDrawBuffer(GL_BACK);
6480 checkGLcall("glDrawBuffer(GL_BACK)");
6481 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6482 Swapchain->presentParms.BackBufferCount = 1;
6484 /* That makes problems - disable for now */
6485 /* glDrawBuffer(GL_FRONT); */
6486 checkGLcall("glDrawBuffer(GL_FRONT)");
6487 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6488 Swapchain->presentParms.BackBufferCount = 0;
6492 if(Swapchain->backBuffer[0])
6494 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6495 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
6497 Swapchain->backBuffer[0] = Back;
6499 if(Swapchain->backBuffer[0]) {
6500 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6501 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
6503 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6504 Swapchain->backBuffer = NULL;
6512 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6513 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6514 *ppZStencilSurface = This->stencilBufferTarget;
6515 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6517 if(*ppZStencilSurface != NULL) {
6518 /* Note inc ref on returned surface */
6519 IWineD3DSurface_AddRef(*ppZStencilSurface);
6522 return WINED3DERR_NOTFOUND;
6526 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6527 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6529 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6530 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6531 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6533 POINT offset = {0, 0};
6535 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6536 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6537 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6538 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6541 case WINED3DTEXF_LINEAR:
6542 gl_filter = GL_LINEAR;
6546 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6547 case WINED3DTEXF_NONE:
6548 case WINED3DTEXF_POINT:
6549 gl_filter = GL_NEAREST;
6553 /* Attach src surface to src fbo */
6554 src_swapchain = get_swapchain(src_surface);
6555 if (src_swapchain) {
6556 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6558 TRACE("Source surface %p is onscreen\n", src_surface);
6559 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6560 /* Make sure the drawable is up to date. In the offscreen case
6561 * attach_surface_fbo() implicitly takes care of this. */
6562 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6564 if(buffer == GL_FRONT) {
6567 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6568 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6569 h = windowsize.bottom - windowsize.top;
6570 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6571 src_rect->y1 = offset.y + h - src_rect->y1;
6572 src_rect->y2 = offset.y + h - src_rect->y2;
6574 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6575 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6579 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6580 glReadBuffer(buffer);
6581 checkGLcall("glReadBuffer()");
6583 TRACE("Source surface %p is offscreen\n", src_surface);
6585 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6586 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6587 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6588 checkGLcall("glReadBuffer()");
6589 context_attach_depth_stencil_fbo(This, GL_READ_FRAMEBUFFER_EXT, NULL, FALSE);
6593 /* Attach dst surface to dst fbo */
6594 dst_swapchain = get_swapchain(dst_surface);
6595 if (dst_swapchain) {
6596 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6598 TRACE("Destination surface %p is onscreen\n", dst_surface);
6599 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6600 /* Make sure the drawable is up to date. In the offscreen case
6601 * attach_surface_fbo() implicitly takes care of this. */
6602 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6604 if(buffer == GL_FRONT) {
6607 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6608 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6609 h = windowsize.bottom - windowsize.top;
6610 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6611 dst_rect->y1 = offset.y + h - dst_rect->y1;
6612 dst_rect->y2 = offset.y + h - dst_rect->y2;
6614 /* Screen coords = window coords, surface height = window height */
6615 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6616 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6620 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6621 glDrawBuffer(buffer);
6622 checkGLcall("glDrawBuffer()");
6624 TRACE("Destination surface %p is offscreen\n", dst_surface);
6626 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6627 if(!src_swapchain) {
6628 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6632 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6633 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6634 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6635 checkGLcall("glDrawBuffer()");
6636 context_attach_depth_stencil_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, NULL, FALSE);
6638 glDisable(GL_SCISSOR_TEST);
6639 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6642 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6643 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6644 checkGLcall("glBlitFramebuffer()");
6646 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6647 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6648 checkGLcall("glBlitFramebuffer()");
6651 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6653 if (This->activeContext->current_fbo) {
6654 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6656 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6657 checkGLcall("glBindFramebuffer()");
6660 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6661 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6662 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6663 glDrawBuffer(GL_BACK);
6664 checkGLcall("glDrawBuffer()");
6669 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6670 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6671 WINED3DVIEWPORT viewport;
6673 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6675 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6676 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6677 This, RenderTargetIndex, GL_LIMITS(buffers));
6678 return WINED3DERR_INVALIDCALL;
6681 /* MSDN says that null disables the render target
6682 but a device must always be associated with a render target
6683 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6685 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6686 FIXME("Trying to set render target 0 to NULL\n");
6687 return WINED3DERR_INVALIDCALL;
6689 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6690 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);
6691 return WINED3DERR_INVALIDCALL;
6694 /* If we are trying to set what we already have, don't bother */
6695 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6696 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6699 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6700 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6701 This->render_targets[RenderTargetIndex] = pRenderTarget;
6703 /* Render target 0 is special */
6704 if(RenderTargetIndex == 0) {
6705 /* Finally, reset the viewport as the MSDN states. */
6706 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6707 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6710 viewport.MaxZ = 1.0f;
6711 viewport.MinZ = 0.0f;
6712 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6713 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6714 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6716 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6721 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6722 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6723 HRESULT hr = WINED3D_OK;
6724 IWineD3DSurface *tmp;
6726 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6728 if (pNewZStencil == This->stencilBufferTarget) {
6729 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6731 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6732 * depending on the renter target implementation being used.
6733 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6734 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6735 * stencil buffer and incur an extra memory overhead
6736 ******************************************************/
6738 if (This->stencilBufferTarget) {
6739 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6740 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6741 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6743 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6744 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6745 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6749 tmp = This->stencilBufferTarget;
6750 This->stencilBufferTarget = pNewZStencil;
6751 /* should we be calling the parent or the wined3d surface? */
6752 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6753 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6756 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6757 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6758 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6759 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6760 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6767 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6768 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6769 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6770 /* TODO: the use of Impl is deprecated. */
6771 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6772 WINED3DLOCKED_RECT lockedRect;
6774 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6776 /* some basic validation checks */
6777 if(This->cursorTexture) {
6778 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6780 glDeleteTextures(1, &This->cursorTexture);
6782 This->cursorTexture = 0;
6785 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6786 This->haveHardwareCursor = TRUE;
6788 This->haveHardwareCursor = FALSE;
6791 WINED3DLOCKED_RECT rect;
6793 /* MSDN: Cursor must be A8R8G8B8 */
6794 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format_desc->format)
6796 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6797 return WINED3DERR_INVALIDCALL;
6800 /* MSDN: Cursor must be smaller than the display mode */
6801 if(pSur->currentDesc.Width > This->ddraw_width ||
6802 pSur->currentDesc.Height > This->ddraw_height) {
6803 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);
6804 return WINED3DERR_INVALIDCALL;
6807 if (!This->haveHardwareCursor) {
6808 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6810 /* Do not store the surface's pointer because the application may
6811 * release it after setting the cursor image. Windows doesn't
6812 * addref the set surface, so we can't do this either without
6813 * creating circular refcount dependencies. Copy out the gl texture
6816 This->cursorWidth = pSur->currentDesc.Width;
6817 This->cursorHeight = pSur->currentDesc.Height;
6818 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6820 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION);
6821 char *mem, *bits = rect.pBits;
6822 GLint intfmt = glDesc->glInternal;
6823 GLint format = glDesc->glFormat;
6824 GLint type = glDesc->glType;
6825 INT height = This->cursorHeight;
6826 INT width = This->cursorWidth;
6827 INT bpp = glDesc->byte_count;
6830 /* Reformat the texture memory (pitch and width can be
6832 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6833 for(i = 0; i < height; i++)
6834 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6835 IWineD3DSurface_UnlockRect(pCursorBitmap);
6838 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6839 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6840 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6843 /* Make sure that a proper texture unit is selected */
6844 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6845 checkGLcall("glActiveTextureARB");
6846 sampler = This->rev_tex_unit_map[0];
6847 if (sampler != -1) {
6848 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6850 /* Create a new cursor texture */
6851 glGenTextures(1, &This->cursorTexture);
6852 checkGLcall("glGenTextures");
6853 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6854 checkGLcall("glBindTexture");
6855 /* Copy the bitmap memory into the cursor texture */
6856 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6857 HeapFree(GetProcessHeap(), 0, mem);
6858 checkGLcall("glTexImage2D");
6860 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6861 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6862 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6869 FIXME("A cursor texture was not returned.\n");
6870 This->cursorTexture = 0;
6875 /* Draw a hardware cursor */
6876 ICONINFO cursorInfo;
6878 /* Create and clear maskBits because it is not needed for
6879 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6881 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6882 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6883 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6884 WINED3DLOCK_NO_DIRTY_UPDATE |
6885 WINED3DLOCK_READONLY
6887 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6888 pSur->currentDesc.Height);
6890 cursorInfo.fIcon = FALSE;
6891 cursorInfo.xHotspot = XHotSpot;
6892 cursorInfo.yHotspot = YHotSpot;
6893 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6894 pSur->currentDesc.Height, 1,
6896 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6897 pSur->currentDesc.Height, 1,
6898 32, lockedRect.pBits);
6899 IWineD3DSurface_UnlockRect(pCursorBitmap);
6900 /* Create our cursor and clean up. */
6901 cursor = CreateIconIndirect(&cursorInfo);
6903 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6904 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6905 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6906 This->hardwareCursor = cursor;
6907 HeapFree(GetProcessHeap(), 0, maskBits);
6911 This->xHotSpot = XHotSpot;
6912 This->yHotSpot = YHotSpot;
6916 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6917 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6918 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6920 This->xScreenSpace = XScreenSpace;
6921 This->yScreenSpace = YScreenSpace;
6927 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6928 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6929 BOOL oldVisible = This->bCursorVisible;
6932 TRACE("(%p) : visible(%d)\n", This, bShow);
6935 * When ShowCursor is first called it should make the cursor appear at the OS's last
6936 * known cursor position. Because of this, some applications just repetitively call
6937 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6940 This->xScreenSpace = pt.x;
6941 This->yScreenSpace = pt.y;
6943 if (This->haveHardwareCursor) {
6944 This->bCursorVisible = bShow;
6946 SetCursor(This->hardwareCursor);
6952 if (This->cursorTexture)
6953 This->bCursorVisible = bShow;
6959 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6960 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6961 IWineD3DResourceImpl *resource;
6962 TRACE("(%p) : state (%u)\n", This, This->state);
6964 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6965 switch (This->state) {
6968 case WINED3DERR_DEVICELOST:
6970 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6971 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6972 return WINED3DERR_DEVICENOTRESET;
6974 return WINED3DERR_DEVICELOST;
6976 case WINED3DERR_DRIVERINTERNALERROR:
6977 return WINED3DERR_DRIVERINTERNALERROR;
6981 return WINED3DERR_DRIVERINTERNALERROR;
6985 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6986 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6987 /** FIXME: Resource tracking needs to be done,
6988 * The closes we can do to this is set the priorities of all managed textures low
6989 * and then reset them.
6990 ***********************************************************/
6991 FIXME("(%p) : stub\n", This);
6995 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6997 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6999 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7000 if(surface->Flags & SFLAG_DIBSECTION) {
7001 /* Release the DC */
7002 SelectObject(surface->hDC, surface->dib.holdbitmap);
7003 DeleteDC(surface->hDC);
7004 /* Release the DIB section */
7005 DeleteObject(surface->dib.DIBsection);
7006 surface->dib.bitmap_data = NULL;
7007 surface->resource.allocatedMemory = NULL;
7008 surface->Flags &= ~SFLAG_DIBSECTION;
7010 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7011 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7012 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
7013 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
7014 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7015 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7017 surface->pow2Width = surface->pow2Height = 1;
7018 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7019 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7021 surface->glRect.left = 0;
7022 surface->glRect.top = 0;
7023 surface->glRect.right = surface->pow2Width;
7024 surface->glRect.bottom = surface->pow2Height;
7026 if(surface->glDescription.textureName) {
7027 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7029 glDeleteTextures(1, &surface->glDescription.textureName);
7031 surface->glDescription.textureName = 0;
7032 surface->Flags &= ~SFLAG_CLIENT;
7034 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7035 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7036 surface->Flags |= SFLAG_NONPOW2;
7038 surface->Flags &= ~SFLAG_NONPOW2;
7040 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7041 surface->resource.allocatedMemory = NULL;
7042 surface->resource.heapMemory = NULL;
7043 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7044 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7045 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7046 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7048 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7052 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7053 TRACE("Unloading resource %p\n", resource);
7054 IWineD3DResource_UnLoad(resource);
7055 IWineD3DResource_Release(resource);
7059 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
7062 WINED3DDISPLAYMODE m;
7065 /* All Windowed modes are supported, as is leaving the current mode */
7066 if(pp->Windowed) return TRUE;
7067 if(!pp->BackBufferWidth) return TRUE;
7068 if(!pp->BackBufferHeight) return TRUE;
7070 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7071 for(i = 0; i < count; i++) {
7072 memset(&m, 0, sizeof(m));
7073 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7075 ERR("EnumAdapterModes failed\n");
7077 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7078 /* Mode found, it is supported */
7082 /* Mode not found -> not supported */
7086 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7087 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7088 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7090 IWineD3DBaseShaderImpl *shader;
7092 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7093 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7094 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7098 if(This->depth_blt_texture) {
7099 glDeleteTextures(1, &This->depth_blt_texture);
7100 This->depth_blt_texture = 0;
7102 if (This->depth_blt_rb) {
7103 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7104 This->depth_blt_rb = 0;
7105 This->depth_blt_rb_w = 0;
7106 This->depth_blt_rb_h = 0;
7110 This->blitter->free_private(iface);
7111 This->frag_pipe->free_private(iface);
7112 This->shader_backend->shader_free_private(iface);
7115 for (i = 0; i < GL_LIMITS(textures); i++) {
7116 /* Textures are recreated below */
7117 glDeleteTextures(1, &This->dummyTextureName[i]);
7118 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7119 This->dummyTextureName[i] = 0;
7123 while(This->numContexts) {
7124 DestroyContext(This, This->contexts[0]);
7126 This->activeContext = NULL;
7127 HeapFree(GetProcessHeap(), 0, swapchain->context);
7128 swapchain->context = NULL;
7129 swapchain->num_contexts = 0;
7132 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7133 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7134 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7136 IWineD3DSurfaceImpl *target;
7138 /* Recreate the primary swapchain's context */
7139 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7140 if(swapchain->backBuffer) {
7141 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7143 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7145 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7146 &swapchain->presentParms);
7147 swapchain->num_contexts = 1;
7148 This->activeContext = swapchain->context[0];
7150 create_dummy_textures(This);
7152 hr = This->shader_backend->shader_alloc_private(iface);
7154 ERR("Failed to recreate shader private data\n");
7157 hr = This->frag_pipe->alloc_private(iface);
7159 TRACE("Fragment pipeline private data couldn't be allocated\n");
7162 hr = This->blitter->alloc_private(iface);
7164 TRACE("Blitter private data couldn't be allocated\n");
7171 This->blitter->free_private(iface);
7172 This->frag_pipe->free_private(iface);
7173 This->shader_backend->shader_free_private(iface);
7177 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7178 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7179 IWineD3DSwapChainImpl *swapchain;
7181 BOOL DisplayModeChanged = FALSE;
7182 WINED3DDISPLAYMODE mode;
7183 TRACE("(%p)\n", This);
7185 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7187 ERR("Failed to get the first implicit swapchain\n");
7191 if(!is_display_mode_supported(This, pPresentationParameters)) {
7192 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7193 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7194 pPresentationParameters->BackBufferHeight);
7195 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
7196 return WINED3DERR_INVALIDCALL;
7199 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7200 * on an existing gl context, so there's no real need for recreation.
7202 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7204 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7206 TRACE("New params:\n");
7207 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7208 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7209 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7210 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7211 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7212 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7213 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7214 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7215 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7216 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7217 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7218 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7219 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7221 /* No special treatment of these parameters. Just store them */
7222 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7223 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7224 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7225 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7227 /* What to do about these? */
7228 if(pPresentationParameters->BackBufferCount != 0 &&
7229 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7230 ERR("Cannot change the back buffer count yet\n");
7232 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7233 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7234 ERR("Cannot change the back buffer format yet\n");
7236 if(pPresentationParameters->hDeviceWindow != NULL &&
7237 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7238 ERR("Cannot change the device window yet\n");
7240 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7243 TRACE("Creating the depth stencil buffer\n");
7245 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
7247 pPresentationParameters->BackBufferWidth,
7248 pPresentationParameters->BackBufferHeight,
7249 pPresentationParameters->AutoDepthStencilFormat,
7250 pPresentationParameters->MultiSampleType,
7251 pPresentationParameters->MultiSampleQuality,
7253 &This->auto_depth_stencil_buffer);
7256 ERR("Failed to create the depth stencil buffer\n");
7257 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7258 return WINED3DERR_INVALIDCALL;
7262 /* Reset the depth stencil */
7263 if (pPresentationParameters->EnableAutoDepthStencil)
7264 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7266 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7268 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7270 if(pPresentationParameters->Windowed) {
7271 mode.Width = swapchain->orig_width;
7272 mode.Height = swapchain->orig_height;
7273 mode.RefreshRate = 0;
7274 mode.Format = swapchain->presentParms.BackBufferFormat;
7276 mode.Width = pPresentationParameters->BackBufferWidth;
7277 mode.Height = pPresentationParameters->BackBufferHeight;
7278 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7279 mode.Format = swapchain->presentParms.BackBufferFormat;
7282 /* Should Width == 800 && Height == 0 set 800x600? */
7283 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7284 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7285 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7289 if(!pPresentationParameters->Windowed) {
7290 DisplayModeChanged = TRUE;
7292 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7293 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7295 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7296 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7297 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7299 if(This->auto_depth_stencil_buffer) {
7300 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7304 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7305 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7306 DisplayModeChanged) {
7308 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7310 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7311 if(swapchain->presentParms.Windowed) {
7312 /* switch from windowed to fs */
7313 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7314 pPresentationParameters->BackBufferWidth,
7315 pPresentationParameters->BackBufferHeight);
7317 /* Fullscreen -> fullscreen mode change */
7318 MoveWindow(swapchain->win_handle, 0, 0,
7319 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7322 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7323 /* Fullscreen -> windowed switch */
7324 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7326 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7327 } else if(!pPresentationParameters->Windowed) {
7328 DWORD style = This->style, exStyle = This->exStyle;
7329 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7330 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7331 * Reset to clear up their mess. Guild Wars also loses the device during that.
7335 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7336 pPresentationParameters->BackBufferWidth,
7337 pPresentationParameters->BackBufferHeight);
7338 This->style = style;
7339 This->exStyle = exStyle;
7342 TRACE("Resetting stateblock\n");
7343 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
7344 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
7346 /* Note: No parent needed for initial internal stateblock */
7347 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
7348 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7349 else TRACE("Created stateblock %p\n", This->stateBlock);
7350 This->updateStateBlock = This->stateBlock;
7351 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
7353 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7355 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7358 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7359 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7361 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7367 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7368 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7369 /** FIXME: always true at the moment **/
7370 if(!bEnableDialogs) {
7371 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7377 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7379 TRACE("(%p) : pParameters %p\n", This, pParameters);
7381 *pParameters = This->createParms;
7385 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7386 IWineD3DSwapChain *swapchain;
7388 TRACE("Relaying to swapchain\n");
7390 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7391 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7392 IWineD3DSwapChain_Release(swapchain);
7397 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7398 IWineD3DSwapChain *swapchain;
7400 TRACE("Relaying to swapchain\n");
7402 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7403 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7404 IWineD3DSwapChain_Release(swapchain);
7410 /** ********************************************************
7411 * Notification functions
7412 ** ********************************************************/
7413 /** This function must be called in the release of a resource when ref == 0,
7414 * the contents of resource must still be correct,
7415 * any handles to other resource held by the caller must be closed
7416 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7417 *****************************************************/
7418 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7420 TRACE("(%p) : Adding resource %p\n", This, resource);
7422 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7425 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7427 TRACE("(%p) : Removing resource %p\n", This, resource);
7429 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7432 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7434 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7437 TRACE("(%p) : resource %p\n", This, resource);
7439 context_resource_released((IWineD3DDevice *)This, resource, type);
7442 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7443 case WINED3DRTYPE_SURFACE: {
7446 /* Cleanup any FBO attachments if d3d is enabled */
7447 if(This->d3d_initialized) {
7448 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7449 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7451 TRACE("Last active render target destroyed\n");
7452 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7453 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7454 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7455 * and the lastActiveRenderTarget member shouldn't matter
7458 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7459 TRACE("Activating primary back buffer\n");
7460 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7461 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7462 /* Single buffering environment */
7463 TRACE("Activating primary front buffer\n");
7464 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7466 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7467 /* Implicit render target destroyed, that means the device is being destroyed
7468 * whatever we set here, it shouldn't matter
7470 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7473 /* May happen during ddraw uninitialization */
7474 TRACE("Render target set, but swapchain does not exist!\n");
7475 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7479 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7480 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7481 This->render_targets[i] = NULL;
7484 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7485 This->stencilBufferTarget = NULL;
7491 case WINED3DRTYPE_TEXTURE:
7492 case WINED3DRTYPE_CUBETEXTURE:
7493 case WINED3DRTYPE_VOLUMETEXTURE:
7494 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7495 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7496 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7497 This->stateBlock->textures[counter] = NULL;
7499 if (This->updateStateBlock != This->stateBlock ){
7500 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7501 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7502 This->updateStateBlock->textures[counter] = NULL;
7507 case WINED3DRTYPE_VOLUME:
7508 /* TODO: nothing really? */
7510 case WINED3DRTYPE_BUFFER:
7513 TRACE("Cleaning up stream pointers\n");
7515 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7516 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7517 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7519 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7520 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7521 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7522 This->updateStateBlock->streamSource[streamNumber] = 0;
7523 /* Set changed flag? */
7526 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) */
7527 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7528 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7529 This->stateBlock->streamSource[streamNumber] = 0;
7534 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7535 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7536 This->updateStateBlock->pIndexData = NULL;
7539 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7540 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7541 This->stateBlock->pIndexData = NULL;
7548 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7553 /* Remove the resource from the resourceStore */
7554 device_resource_remove(This, resource);
7556 TRACE("Resource released\n");
7560 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7561 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7562 IWineD3DResourceImpl *resource, *cursor;
7564 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7566 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7567 TRACE("enumerating resource %p\n", resource);
7568 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7569 ret = pCallback((IWineD3DResource *) resource, pData);
7570 if(ret == S_FALSE) {
7571 TRACE("Canceling enumeration\n");
7578 /**********************************************************
7579 * IWineD3DDevice VTbl follows
7580 **********************************************************/
7582 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7584 /*** IUnknown methods ***/
7585 IWineD3DDeviceImpl_QueryInterface,
7586 IWineD3DDeviceImpl_AddRef,
7587 IWineD3DDeviceImpl_Release,
7588 /*** IWineD3DDevice methods ***/
7589 IWineD3DDeviceImpl_GetParent,
7590 /*** Creation methods**/
7591 IWineD3DDeviceImpl_CreateBuffer,
7592 IWineD3DDeviceImpl_CreateVertexBuffer,
7593 IWineD3DDeviceImpl_CreateIndexBuffer,
7594 IWineD3DDeviceImpl_CreateStateBlock,
7595 IWineD3DDeviceImpl_CreateSurface,
7596 IWineD3DDeviceImpl_CreateRendertargetView,
7597 IWineD3DDeviceImpl_CreateTexture,
7598 IWineD3DDeviceImpl_CreateVolumeTexture,
7599 IWineD3DDeviceImpl_CreateVolume,
7600 IWineD3DDeviceImpl_CreateCubeTexture,
7601 IWineD3DDeviceImpl_CreateQuery,
7602 IWineD3DDeviceImpl_CreateSwapChain,
7603 IWineD3DDeviceImpl_CreateVertexDeclaration,
7604 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7605 IWineD3DDeviceImpl_CreateVertexShader,
7606 IWineD3DDeviceImpl_CreatePixelShader,
7607 IWineD3DDeviceImpl_CreatePalette,
7608 /*** Odd functions **/
7609 IWineD3DDeviceImpl_Init3D,
7610 IWineD3DDeviceImpl_InitGDI,
7611 IWineD3DDeviceImpl_Uninit3D,
7612 IWineD3DDeviceImpl_UninitGDI,
7613 IWineD3DDeviceImpl_SetMultithreaded,
7614 IWineD3DDeviceImpl_EvictManagedResources,
7615 IWineD3DDeviceImpl_GetAvailableTextureMem,
7616 IWineD3DDeviceImpl_GetBackBuffer,
7617 IWineD3DDeviceImpl_GetCreationParameters,
7618 IWineD3DDeviceImpl_GetDeviceCaps,
7619 IWineD3DDeviceImpl_GetDirect3D,
7620 IWineD3DDeviceImpl_GetDisplayMode,
7621 IWineD3DDeviceImpl_SetDisplayMode,
7622 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7623 IWineD3DDeviceImpl_GetRasterStatus,
7624 IWineD3DDeviceImpl_GetSwapChain,
7625 IWineD3DDeviceImpl_Reset,
7626 IWineD3DDeviceImpl_SetDialogBoxMode,
7627 IWineD3DDeviceImpl_SetCursorProperties,
7628 IWineD3DDeviceImpl_SetCursorPosition,
7629 IWineD3DDeviceImpl_ShowCursor,
7630 IWineD3DDeviceImpl_TestCooperativeLevel,
7631 /*** Getters and setters **/
7632 IWineD3DDeviceImpl_SetClipPlane,
7633 IWineD3DDeviceImpl_GetClipPlane,
7634 IWineD3DDeviceImpl_SetClipStatus,
7635 IWineD3DDeviceImpl_GetClipStatus,
7636 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7637 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7638 IWineD3DDeviceImpl_SetDepthStencilSurface,
7639 IWineD3DDeviceImpl_GetDepthStencilSurface,
7640 IWineD3DDeviceImpl_SetGammaRamp,
7641 IWineD3DDeviceImpl_GetGammaRamp,
7642 IWineD3DDeviceImpl_SetIndices,
7643 IWineD3DDeviceImpl_GetIndices,
7644 IWineD3DDeviceImpl_SetBaseVertexIndex,
7645 IWineD3DDeviceImpl_GetBaseVertexIndex,
7646 IWineD3DDeviceImpl_SetLight,
7647 IWineD3DDeviceImpl_GetLight,
7648 IWineD3DDeviceImpl_SetLightEnable,
7649 IWineD3DDeviceImpl_GetLightEnable,
7650 IWineD3DDeviceImpl_SetMaterial,
7651 IWineD3DDeviceImpl_GetMaterial,
7652 IWineD3DDeviceImpl_SetNPatchMode,
7653 IWineD3DDeviceImpl_GetNPatchMode,
7654 IWineD3DDeviceImpl_SetPaletteEntries,
7655 IWineD3DDeviceImpl_GetPaletteEntries,
7656 IWineD3DDeviceImpl_SetPixelShader,
7657 IWineD3DDeviceImpl_GetPixelShader,
7658 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7659 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7660 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7661 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7662 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7663 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7664 IWineD3DDeviceImpl_SetRenderState,
7665 IWineD3DDeviceImpl_GetRenderState,
7666 IWineD3DDeviceImpl_SetRenderTarget,
7667 IWineD3DDeviceImpl_GetRenderTarget,
7668 IWineD3DDeviceImpl_SetFrontBackBuffers,
7669 IWineD3DDeviceImpl_SetSamplerState,
7670 IWineD3DDeviceImpl_GetSamplerState,
7671 IWineD3DDeviceImpl_SetScissorRect,
7672 IWineD3DDeviceImpl_GetScissorRect,
7673 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7674 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7675 IWineD3DDeviceImpl_SetStreamSource,
7676 IWineD3DDeviceImpl_GetStreamSource,
7677 IWineD3DDeviceImpl_SetStreamSourceFreq,
7678 IWineD3DDeviceImpl_GetStreamSourceFreq,
7679 IWineD3DDeviceImpl_SetTexture,
7680 IWineD3DDeviceImpl_GetTexture,
7681 IWineD3DDeviceImpl_SetTextureStageState,
7682 IWineD3DDeviceImpl_GetTextureStageState,
7683 IWineD3DDeviceImpl_SetTransform,
7684 IWineD3DDeviceImpl_GetTransform,
7685 IWineD3DDeviceImpl_SetVertexDeclaration,
7686 IWineD3DDeviceImpl_GetVertexDeclaration,
7687 IWineD3DDeviceImpl_SetVertexShader,
7688 IWineD3DDeviceImpl_GetVertexShader,
7689 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7690 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7691 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7692 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7693 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7694 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7695 IWineD3DDeviceImpl_SetViewport,
7696 IWineD3DDeviceImpl_GetViewport,
7697 IWineD3DDeviceImpl_MultiplyTransform,
7698 IWineD3DDeviceImpl_ValidateDevice,
7699 IWineD3DDeviceImpl_ProcessVertices,
7700 /*** State block ***/
7701 IWineD3DDeviceImpl_BeginStateBlock,
7702 IWineD3DDeviceImpl_EndStateBlock,
7703 /*** Scene management ***/
7704 IWineD3DDeviceImpl_BeginScene,
7705 IWineD3DDeviceImpl_EndScene,
7706 IWineD3DDeviceImpl_Present,
7707 IWineD3DDeviceImpl_Clear,
7708 IWineD3DDeviceImpl_ClearRendertargetView,
7710 IWineD3DDeviceImpl_SetPrimitiveType,
7711 IWineD3DDeviceImpl_GetPrimitiveType,
7712 IWineD3DDeviceImpl_DrawPrimitive,
7713 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7714 IWineD3DDeviceImpl_DrawPrimitiveUP,
7715 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7716 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7717 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7718 IWineD3DDeviceImpl_DrawRectPatch,
7719 IWineD3DDeviceImpl_DrawTriPatch,
7720 IWineD3DDeviceImpl_DeletePatch,
7721 IWineD3DDeviceImpl_ColorFill,
7722 IWineD3DDeviceImpl_UpdateTexture,
7723 IWineD3DDeviceImpl_UpdateSurface,
7724 IWineD3DDeviceImpl_GetFrontBufferData,
7725 /*** object tracking ***/
7726 IWineD3DDeviceImpl_EnumResources
7729 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7730 WINED3DRS_ALPHABLENDENABLE ,
7731 WINED3DRS_ALPHAFUNC ,
7732 WINED3DRS_ALPHAREF ,
7733 WINED3DRS_ALPHATESTENABLE ,
7735 WINED3DRS_COLORWRITEENABLE ,
7736 WINED3DRS_DESTBLEND ,
7737 WINED3DRS_DITHERENABLE ,
7738 WINED3DRS_FILLMODE ,
7739 WINED3DRS_FOGDENSITY ,
7741 WINED3DRS_FOGSTART ,
7742 WINED3DRS_LASTPIXEL ,
7743 WINED3DRS_SHADEMODE ,
7744 WINED3DRS_SRCBLEND ,
7745 WINED3DRS_STENCILENABLE ,
7746 WINED3DRS_STENCILFAIL ,
7747 WINED3DRS_STENCILFUNC ,
7748 WINED3DRS_STENCILMASK ,
7749 WINED3DRS_STENCILPASS ,
7750 WINED3DRS_STENCILREF ,
7751 WINED3DRS_STENCILWRITEMASK ,
7752 WINED3DRS_STENCILZFAIL ,
7753 WINED3DRS_TEXTUREFACTOR ,
7764 WINED3DRS_ZWRITEENABLE
7767 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7768 WINED3DTSS_ALPHAARG0 ,
7769 WINED3DTSS_ALPHAARG1 ,
7770 WINED3DTSS_ALPHAARG2 ,
7771 WINED3DTSS_ALPHAOP ,
7772 WINED3DTSS_BUMPENVLOFFSET ,
7773 WINED3DTSS_BUMPENVLSCALE ,
7774 WINED3DTSS_BUMPENVMAT00 ,
7775 WINED3DTSS_BUMPENVMAT01 ,
7776 WINED3DTSS_BUMPENVMAT10 ,
7777 WINED3DTSS_BUMPENVMAT11 ,
7778 WINED3DTSS_COLORARG0 ,
7779 WINED3DTSS_COLORARG1 ,
7780 WINED3DTSS_COLORARG2 ,
7781 WINED3DTSS_COLOROP ,
7782 WINED3DTSS_RESULTARG ,
7783 WINED3DTSS_TEXCOORDINDEX ,
7784 WINED3DTSS_TEXTURETRANSFORMFLAGS
7787 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7788 WINED3DSAMP_ADDRESSU ,
7789 WINED3DSAMP_ADDRESSV ,
7790 WINED3DSAMP_ADDRESSW ,
7791 WINED3DSAMP_BORDERCOLOR ,
7792 WINED3DSAMP_MAGFILTER ,
7793 WINED3DSAMP_MINFILTER ,
7794 WINED3DSAMP_MIPFILTER ,
7795 WINED3DSAMP_MIPMAPLODBIAS ,
7796 WINED3DSAMP_MAXMIPLEVEL ,
7797 WINED3DSAMP_MAXANISOTROPY ,
7798 WINED3DSAMP_SRGBTEXTURE ,
7799 WINED3DSAMP_ELEMENTINDEX
7802 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7804 WINED3DRS_AMBIENTMATERIALSOURCE ,
7805 WINED3DRS_CLIPPING ,
7806 WINED3DRS_CLIPPLANEENABLE ,
7807 WINED3DRS_COLORVERTEX ,
7808 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7809 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7810 WINED3DRS_FOGDENSITY ,
7812 WINED3DRS_FOGSTART ,
7813 WINED3DRS_FOGTABLEMODE ,
7814 WINED3DRS_FOGVERTEXMODE ,
7815 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7816 WINED3DRS_LIGHTING ,
7817 WINED3DRS_LOCALVIEWER ,
7818 WINED3DRS_MULTISAMPLEANTIALIAS ,
7819 WINED3DRS_MULTISAMPLEMASK ,
7820 WINED3DRS_NORMALIZENORMALS ,
7821 WINED3DRS_PATCHEDGESTYLE ,
7822 WINED3DRS_POINTSCALE_A ,
7823 WINED3DRS_POINTSCALE_B ,
7824 WINED3DRS_POINTSCALE_C ,
7825 WINED3DRS_POINTSCALEENABLE ,
7826 WINED3DRS_POINTSIZE ,
7827 WINED3DRS_POINTSIZE_MAX ,
7828 WINED3DRS_POINTSIZE_MIN ,
7829 WINED3DRS_POINTSPRITEENABLE ,
7830 WINED3DRS_RANGEFOGENABLE ,
7831 WINED3DRS_SPECULARMATERIALSOURCE ,
7832 WINED3DRS_TWEENFACTOR ,
7833 WINED3DRS_VERTEXBLEND ,
7834 WINED3DRS_CULLMODE ,
7838 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7839 WINED3DTSS_TEXCOORDINDEX ,
7840 WINED3DTSS_TEXTURETRANSFORMFLAGS
7843 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7844 WINED3DSAMP_DMAPOFFSET
7847 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7848 DWORD rep = This->StateTable[state].representative;
7852 WineD3DContext *context;
7855 for(i = 0; i < This->numContexts; i++) {
7856 context = This->contexts[i];
7857 if(isStateDirty(context, rep)) continue;
7859 context->dirtyArray[context->numDirtyEntries++] = rep;
7862 context->isStateDirty[idx] |= (1 << shift);
7866 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7867 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7868 /* The drawable size of a pbuffer render target is the current pbuffer size
7870 *width = dev->pbufferWidth;
7871 *height = dev->pbufferHeight;
7874 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7875 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7877 *width = This->pow2Width;
7878 *height = This->pow2Height;
7881 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7882 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7883 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7884 * current context's drawable, which is the size of the back buffer of the swapchain
7885 * the active context belongs to. The back buffer of the swapchain is stored as the
7886 * surface the context belongs to.
7888 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7889 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;