2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION This->adapter->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
54 /* static function declarations */
55 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
57 /**********************************************************
58 * Global variable / Constants follow
59 **********************************************************/
60 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
62 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
63 * actually have the same values in GL and D3D. */
64 static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
66 switch(primitive_type)
68 case WINED3DPT_POINTLIST:
71 case WINED3DPT_LINELIST:
74 case WINED3DPT_LINESTRIP:
77 case WINED3DPT_TRIANGLELIST:
80 case WINED3DPT_TRIANGLESTRIP:
81 return GL_TRIANGLE_STRIP;
83 case WINED3DPT_TRIANGLEFAN:
84 return GL_TRIANGLE_FAN;
86 case WINED3DPT_LINELIST_ADJ:
87 return GL_LINES_ADJACENCY_ARB;
89 case WINED3DPT_LINESTRIP_ADJ:
90 return GL_LINE_STRIP_ADJACENCY_ARB;
92 case WINED3DPT_TRIANGLELIST_ADJ:
93 return GL_TRIANGLES_ADJACENCY_ARB;
95 case WINED3DPT_TRIANGLESTRIP_ADJ:
96 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
99 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
104 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
106 switch(primitive_type)
109 return WINED3DPT_POINTLIST;
112 return WINED3DPT_LINELIST;
115 return WINED3DPT_LINESTRIP;
118 return WINED3DPT_TRIANGLELIST;
120 case GL_TRIANGLE_STRIP:
121 return WINED3DPT_TRIANGLESTRIP;
123 case GL_TRIANGLE_FAN:
124 return WINED3DPT_TRIANGLEFAN;
126 case GL_LINES_ADJACENCY_ARB:
127 return WINED3DPT_LINELIST_ADJ;
129 case GL_LINE_STRIP_ADJACENCY_ARB:
130 return WINED3DPT_LINESTRIP_ADJ;
132 case GL_TRIANGLES_ADJACENCY_ARB:
133 return WINED3DPT_TRIANGLELIST_ADJ;
135 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
136 return WINED3DPT_TRIANGLESTRIP_ADJ;
139 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
140 return WINED3DPT_UNDEFINED;
144 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
146 if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && usage_idx == 0)
147 *regnum = WINED3D_FFP_POSITION;
148 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
149 *regnum = WINED3D_FFP_BLENDWEIGHT;
150 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
151 *regnum = WINED3D_FFP_BLENDINDICES;
152 else if (usage == WINED3DDECLUSAGE_NORMAL && usage_idx == 0)
153 *regnum = WINED3D_FFP_NORMAL;
154 else if (usage == WINED3DDECLUSAGE_PSIZE && usage_idx == 0)
155 *regnum = WINED3D_FFP_PSIZE;
156 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 0)
157 *regnum = WINED3D_FFP_DIFFUSE;
158 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1)
159 *regnum = WINED3D_FFP_SPECULAR;
160 else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
161 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
164 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
172 void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
173 BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
175 /* We need to deal with frequency data! */
176 IWineD3DVertexDeclarationImpl *declaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
177 UINT stream_count = This->stateBlock->streamIsUP ? 0 : declaration->num_streams;
178 const DWORD *streams = declaration->streams;
181 memset(stream_info, 0, sizeof(*stream_info));
183 /* Check for transformed vertices, disable vertex shader if present. */
184 stream_info->position_transformed = declaration->position_transformed;
185 if (declaration->position_transformed) use_vshader = FALSE;
187 /* Translate the declaration into strided data. */
188 for (i = 0; i < declaration->element_count; ++i)
190 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
191 GLuint buffer_object = 0;
192 const BYTE *data = NULL;
197 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
198 element, i + 1, declaration->element_count);
200 if (!This->stateBlock->streamSource[element->input_slot]) continue;
202 stride = This->stateBlock->streamStride[element->input_slot];
203 if (This->stateBlock->streamIsUP)
205 TRACE("Stream %u is UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
207 data = (BYTE *)This->stateBlock->streamSource[element->input_slot];
211 TRACE("Stream %u isn't UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
212 data = buffer_get_memory(This->stateBlock->streamSource[element->input_slot], 0, &buffer_object);
214 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
215 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
216 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
217 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
218 * not, drawStridedSlow is needed, including a vertex buffer path. */
219 if (This->stateBlock->loadBaseVertexIndex < 0)
221 WARN("loadBaseVertexIndex is < 0 (%d), not using vbos\n", This->stateBlock->loadBaseVertexIndex);
223 data = ((struct wined3d_buffer *)This->stateBlock->streamSource[element->input_slot])->resource.allocatedMemory;
224 if ((UINT_PTR)data < -This->stateBlock->loadBaseVertexIndex * stride)
226 FIXME("System memory vertex data load offset is negative!\n");
232 if (buffer_object) *fixup = TRUE;
233 else if (*fixup && !use_vshader
234 && (element->usage == WINED3DDECLUSAGE_COLOR
235 || element->usage == WINED3DDECLUSAGE_POSITIONT))
237 static BOOL warned = FALSE;
240 /* This may be bad with the fixed function pipeline. */
241 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
247 data += element->offset;
249 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
253 if (element->output_slot == ~0U)
255 /* TODO: Assuming vertexdeclarations are usually used with the
256 * same or a similar shader, it might be worth it to store the
257 * last used output slot and try that one first. */
258 stride_used = vshader_get_input(This->stateBlock->vertexShader,
259 element->usage, element->usage_idx, &idx);
263 idx = element->output_slot;
269 if (!element->ffp_valid)
271 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
272 debug_d3dformat(element->format_desc->format), debug_d3ddeclusage(element->usage));
277 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
283 TRACE("Load %s array %u [usage %s, usage_idx %u, "
284 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
285 use_vshader ? "shader": "fixed function", idx,
286 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
287 element->offset, stride, debug_d3dformat(element->format_desc->format), buffer_object);
289 stream_info->elements[idx].format_desc = element->format_desc;
290 stream_info->elements[idx].stride = stride;
291 stream_info->elements[idx].data = data;
292 stream_info->elements[idx].stream_idx = element->input_slot;
293 stream_info->elements[idx].buffer_object = buffer_object;
295 if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA) && element->format_desc->format == WINED3DFMT_A8R8G8B8)
297 stream_info->swizzle_map |= 1 << idx;
299 stream_info->use_map |= 1 << idx;
303 /* Now call PreLoad on all the vertex buffers. In the very rare case
304 * that the buffers stopps converting PreLoad will dirtify the VDECL again.
305 * The vertex buffer can now use the strided structure in the device instead of finding its
308 * NULL streams won't be recorded in the array, UP streams won't be either. A stream is only
310 for (i = 0; i < stream_count; ++i)
312 IWineD3DBuffer *vb = This->stateBlock->streamSource[streams[i]];
313 if (vb) IWineD3DBuffer_PreLoad(vb);
317 static void stream_info_element_from_strided(IWineD3DDeviceImpl *This,
318 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
320 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(strided->format, &This->adapter->gl_info);
321 e->format_desc = format_desc;
322 e->stride = strided->dwStride;
323 e->data = strided->lpData;
325 e->buffer_object = 0;
328 void device_stream_info_from_strided(IWineD3DDeviceImpl *This,
329 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
333 memset(stream_info, 0, sizeof(*stream_info));
335 if (strided->position.lpData)
336 stream_info_element_from_strided(This, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
337 if (strided->normal.lpData)
338 stream_info_element_from_strided(This, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
339 if (strided->diffuse.lpData)
340 stream_info_element_from_strided(This, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
341 if (strided->specular.lpData)
342 stream_info_element_from_strided(This, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
344 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
346 if (strided->texCoords[i].lpData)
347 stream_info_element_from_strided(This, &strided->texCoords[i],
348 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
351 stream_info->position_transformed = strided->position_transformed;
353 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
355 if (!stream_info->elements[i].format_desc) continue;
357 if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA) && stream_info->elements[i].format_desc->format == WINED3DFMT_A8R8G8B8)
359 stream_info->swizzle_map |= 1 << i;
361 stream_info->use_map |= 1 << i;
365 /**********************************************************
366 * IUnknown parts follows
367 **********************************************************/
369 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
371 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
373 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
374 if (IsEqualGUID(riid, &IID_IUnknown)
375 || IsEqualGUID(riid, &IID_IWineD3DBase)
376 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
377 IUnknown_AddRef(iface);
382 return E_NOINTERFACE;
385 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
386 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
387 ULONG refCount = InterlockedIncrement(&This->ref);
389 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
393 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
395 ULONG refCount = InterlockedDecrement(&This->ref);
397 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
402 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
403 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
404 This->multistate_funcs[i] = NULL;
407 /* TODO: Clean up all the surfaces and textures! */
408 /* NOTE: You must release the parent if the object was created via a callback
409 ** ***************************/
411 if (!list_empty(&This->resources)) {
412 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
413 dumpResources(&This->resources);
416 if(This->contexts) ERR("Context array not freed!\n");
417 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
418 This->haveHardwareCursor = FALSE;
420 IWineD3D_Release(This->wineD3D);
421 This->wineD3D = NULL;
422 HeapFree(GetProcessHeap(), 0, This);
423 TRACE("Freed device %p\n", This);
429 /**********************************************************
430 * IWineD3DDevice implementation follows
431 **********************************************************/
432 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
433 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
434 *pParent = This->parent;
435 IUnknown_AddRef(This->parent);
439 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface,
440 struct wined3d_buffer_desc *desc, const void *data, IUnknown *parent, IWineD3DBuffer **buffer)
442 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
443 struct wined3d_buffer *object;
446 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
448 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
451 ERR("Failed to allocate memory\n");
452 return E_OUTOFMEMORY;
455 object->vtbl = &wined3d_buffer_vtbl;
456 object->desc = *desc;
458 FIXME("Ignoring access flags (pool)\n");
460 hr = resource_init(&object->resource, WINED3DRTYPE_BUFFER, This, desc->byte_width,
461 desc->usage, WINED3DFMT_UNKNOWN, WINED3DPOOL_MANAGED, parent);
464 WARN("Failed to initialize resource, returning %#x\n", hr);
465 HeapFree(GetProcessHeap(), 0, object);
468 object->buffer_type_hint = GL_ARRAY_BUFFER_ARB;
470 TRACE("Created resource %p\n", object);
472 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
474 TRACE("size %#x, usage=%#x, format %s, memory @ %p, iface @ %p\n", object->resource.size, object->resource.usage,
475 debug_d3dformat(object->resource.format_desc->format), object->resource.allocatedMemory, object);
481 hr = IWineD3DBuffer_Map((IWineD3DBuffer *)object, 0, desc->byte_width, &ptr, 0);
484 ERR("Failed to map buffer, hr %#x\n", hr);
485 IWineD3DBuffer_Release((IWineD3DBuffer *)object);
489 memcpy(ptr, data, desc->byte_width);
491 hr = IWineD3DBuffer_Unmap((IWineD3DBuffer *)object);
494 ERR("Failed to unmap buffer, hr %#x\n", hr);
495 IWineD3DBuffer_Release((IWineD3DBuffer *)object);
500 *buffer = (IWineD3DBuffer *)object;
505 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
506 DWORD FVF, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer, HANDLE *sharedHandle, IUnknown *parent)
508 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
509 /* Dummy format for now */
510 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(WINED3DFMT_VERTEXDATA, &This->adapter->gl_info);
511 struct wined3d_buffer *object;
512 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
517 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
518 *ppVertexBuffer = NULL;
519 return WINED3DERR_INVALIDCALL;
520 } else if(Pool == WINED3DPOOL_SCRATCH) {
521 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
522 * anyway, SCRATCH vertex buffers aren't usable anywhere
524 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
525 *ppVertexBuffer = NULL;
526 return WINED3DERR_INVALIDCALL;
529 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
532 ERR("Out of memory\n");
533 *ppVertexBuffer = NULL;
534 return WINED3DERR_OUTOFVIDEOMEMORY;
537 object->vtbl = &wined3d_buffer_vtbl;
538 hr = resource_init(&object->resource, WINED3DRTYPE_BUFFER, This, Size, Usage, format_desc, Pool, parent);
541 WARN("Failed to initialize resource, returning %#x\n", hr);
542 HeapFree(GetProcessHeap(), 0, object);
543 *ppVertexBuffer = NULL;
546 object->buffer_type_hint = GL_ARRAY_BUFFER_ARB;
548 TRACE("(%p) : Created resource %p\n", This, object);
550 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
552 TRACE("(%p) : Size=%d, Usage=0x%08x, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
553 *ppVertexBuffer = (IWineD3DBuffer *)object;
557 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
558 * drawStridedFast (half-life 2).
560 * Basically converting the vertices in the buffer is quite expensive, and observations
561 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
562 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
564 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
565 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
566 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
567 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
569 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
570 * more. In this call we can convert dx7 buffers too.
572 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
573 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
574 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
575 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
576 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
577 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
578 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
579 } else if(dxVersion <= 7 && conv) {
580 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
582 object->flags |= WINED3D_BUFFER_CREATEBO;
587 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
588 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DBuffer** ppIndexBuffer,
589 HANDLE *sharedHandle, IUnknown *parent) {
590 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
591 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
592 struct wined3d_buffer *object;
595 TRACE("(%p) Creating index buffer\n", This);
597 /* Allocate the storage for the device */
598 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
601 ERR("Out of memory\n");
602 *ppIndexBuffer = NULL;
603 return WINED3DERR_OUTOFVIDEOMEMORY;
606 object->vtbl = &wined3d_buffer_vtbl;
607 hr = resource_init(&object->resource, WINED3DRTYPE_BUFFER, This, Length, Usage, format_desc, Pool, parent);
610 WARN("Failed to initialize resource, returning %#x\n", hr);
611 HeapFree(GetProcessHeap(), 0, object);
612 *ppIndexBuffer = NULL;
615 object->buffer_type_hint = GL_ELEMENT_ARRAY_BUFFER_ARB;
617 TRACE("(%p) : Created resource %p\n", This, object);
619 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
621 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
622 object->flags |= WINED3D_BUFFER_CREATEBO;
625 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
626 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
627 *ppIndexBuffer = (IWineD3DBuffer *) object;
632 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
634 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
635 IWineD3DStateBlockImpl *object;
639 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
642 ERR("Out of memory\n");
643 *ppStateBlock = NULL;
644 return WINED3DERR_OUTOFVIDEOMEMORY;
647 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
648 object->wineD3DDevice = This;
649 object->parent = parent;
651 object->blockType = Type;
653 *ppStateBlock = (IWineD3DStateBlock *)object;
655 for(i = 0; i < LIGHTMAP_SIZE; i++) {
656 list_init(&object->lightMap[i]);
659 temp_result = allocate_shader_constants(object);
660 if (FAILED(temp_result))
662 HeapFree(GetProcessHeap(), 0, object);
666 /* Special case - Used during initialization to produce a placeholder stateblock
667 so other functions called can update a state block */
668 if (Type == WINED3DSBT_INIT || Type == WINED3DSBT_RECORDED)
670 /* Don't bother increasing the reference count otherwise a device will never
671 be freed due to circular dependencies */
675 /* Otherwise, might as well set the whole state block to the appropriate values */
676 if (This->stateBlock != NULL)
677 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
679 memset(object->streamFreq, 1, sizeof(object->streamFreq));
681 /* Reset the ref and type after kludging it */
682 object->wineD3DDevice = This;
684 object->blockType = Type;
686 TRACE("Updating changed flags appropriate for type %d\n", Type);
688 if (Type == WINED3DSBT_ALL) {
690 TRACE("ALL => Pretend everything has changed\n");
691 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
693 /* Lights are not part of the changed / set structure */
694 for(j = 0; j < LIGHTMAP_SIZE; j++) {
696 LIST_FOR_EACH(e, &object->lightMap[j]) {
697 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
698 light->changed = TRUE;
699 light->enabledChanged = TRUE;
702 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
703 object->contained_render_states[j - 1] = j;
705 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
706 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
707 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
708 object->contained_transform_states[j - 1] = j;
710 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
711 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
712 object->contained_vs_consts_f[j] = j;
714 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
715 for(j = 0; j < MAX_CONST_I; j++) {
716 object->contained_vs_consts_i[j] = j;
718 object->num_contained_vs_consts_i = MAX_CONST_I;
719 for(j = 0; j < MAX_CONST_B; j++) {
720 object->contained_vs_consts_b[j] = j;
722 object->num_contained_vs_consts_b = MAX_CONST_B;
723 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
724 object->contained_ps_consts_f[j] = j;
726 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
727 for(j = 0; j < MAX_CONST_I; j++) {
728 object->contained_ps_consts_i[j] = j;
730 object->num_contained_ps_consts_i = MAX_CONST_I;
731 for(j = 0; j < MAX_CONST_B; j++) {
732 object->contained_ps_consts_b[j] = j;
734 object->num_contained_ps_consts_b = MAX_CONST_B;
735 for(i = 0; i < MAX_TEXTURES; i++) {
736 for (j = 0; j <= WINED3D_HIGHEST_TEXTURE_STATE; ++j)
738 object->contained_tss_states[object->num_contained_tss_states].stage = i;
739 object->contained_tss_states[object->num_contained_tss_states].state = j;
740 object->num_contained_tss_states++;
743 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
744 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
745 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
746 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
747 object->num_contained_sampler_states++;
751 for(i = 0; i < MAX_STREAMS; i++) {
752 if(object->streamSource[i]) {
753 IWineD3DBuffer_AddRef(object->streamSource[i]);
756 if(object->pIndexData) {
757 IWineD3DBuffer_AddRef(object->pIndexData);
759 if(object->vertexShader) {
760 IWineD3DVertexShader_AddRef(object->vertexShader);
762 if(object->pixelShader) {
763 IWineD3DPixelShader_AddRef(object->pixelShader);
766 } else if (Type == WINED3DSBT_PIXELSTATE) {
768 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
769 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
771 object->changed.pixelShader = TRUE;
773 /* Pixel Shader Constants */
774 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
775 object->contained_ps_consts_f[i] = i;
776 object->changed.pixelShaderConstantsF[i] = TRUE;
778 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
779 for (i = 0; i < MAX_CONST_B; ++i) {
780 object->contained_ps_consts_b[i] = i;
781 object->changed.pixelShaderConstantsB |= (1 << i);
783 object->num_contained_ps_consts_b = MAX_CONST_B;
784 for (i = 0; i < MAX_CONST_I; ++i) {
785 object->contained_ps_consts_i[i] = i;
786 object->changed.pixelShaderConstantsI |= (1 << i);
788 object->num_contained_ps_consts_i = MAX_CONST_I;
790 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
791 DWORD rs = SavedPixelStates_R[i];
792 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
793 object->contained_render_states[i] = rs;
795 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
796 for (j = 0; j < MAX_TEXTURES; j++) {
797 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
798 DWORD state = SavedPixelStates_T[i];
799 object->changed.textureState[j] |= 1 << state;
800 object->contained_tss_states[object->num_contained_tss_states].stage = j;
801 object->contained_tss_states[object->num_contained_tss_states].state = state;
802 object->num_contained_tss_states++;
805 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
806 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
807 DWORD state = SavedPixelStates_S[i];
808 object->changed.samplerState[j] |= 1 << state;
809 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
810 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
811 object->num_contained_sampler_states++;
814 if(object->pixelShader) {
815 IWineD3DPixelShader_AddRef(object->pixelShader);
818 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
819 * on them. This makes releasing the buffer easier
821 for(i = 0; i < MAX_STREAMS; i++) {
822 object->streamSource[i] = NULL;
824 object->pIndexData = NULL;
825 object->vertexShader = NULL;
827 } else if (Type == WINED3DSBT_VERTEXSTATE) {
829 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
830 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
832 object->changed.vertexShader = TRUE;
834 /* Vertex Shader Constants */
835 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
836 object->changed.vertexShaderConstantsF[i] = TRUE;
837 object->contained_vs_consts_f[i] = i;
839 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
840 for (i = 0; i < MAX_CONST_B; ++i) {
841 object->contained_vs_consts_b[i] = i;
842 object->changed.vertexShaderConstantsB |= (1 << i);
844 object->num_contained_vs_consts_b = MAX_CONST_B;
845 for (i = 0; i < MAX_CONST_I; ++i) {
846 object->contained_vs_consts_i[i] = i;
847 object->changed.vertexShaderConstantsI |= (1 << i);
849 object->num_contained_vs_consts_i = MAX_CONST_I;
850 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
851 DWORD rs = SavedVertexStates_R[i];
852 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
853 object->contained_render_states[i] = rs;
855 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
856 for (j = 0; j < MAX_TEXTURES; j++) {
857 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
858 DWORD state = SavedVertexStates_T[i];
859 object->changed.textureState[j] |= 1 << state;
860 object->contained_tss_states[object->num_contained_tss_states].stage = j;
861 object->contained_tss_states[object->num_contained_tss_states].state = state;
862 object->num_contained_tss_states++;
865 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
866 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
867 DWORD state = SavedVertexStates_S[i];
868 object->changed.samplerState[j] |= 1 << state;
869 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
870 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
871 object->num_contained_sampler_states++;
875 for(j = 0; j < LIGHTMAP_SIZE; j++) {
877 LIST_FOR_EACH(e, &object->lightMap[j]) {
878 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
879 light->changed = TRUE;
880 light->enabledChanged = TRUE;
884 for(i = 0; i < MAX_STREAMS; i++) {
885 if(object->streamSource[i]) {
886 IWineD3DBuffer_AddRef(object->streamSource[i]);
889 if(object->vertexShader) {
890 IWineD3DVertexShader_AddRef(object->vertexShader);
892 object->pIndexData = NULL;
893 object->pixelShader = NULL;
895 FIXME("Unrecognized state block type %d\n", Type);
898 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
902 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,WINED3DRESOURCETYPE Type, DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample ,DWORD MultisampleQuality, HANDLE* pSharedHandle, WINED3DSURFTYPE Impl, IUnknown *parent) {
903 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
904 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
905 unsigned int Size = 1;
906 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(Format, &GLINFO_LOCATION);
910 TRACE("(%p) Create surface\n",This);
912 if(MultisampleQuality > 0) {
913 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
914 MultisampleQuality=0;
917 /** FIXME: Check that the format is supported
919 *******************************/
921 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
922 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
924 *********************************/
925 mul_4w = (Width + 3) & ~3;
926 mul_4h = (Height + 3) & ~3;
927 if (WINED3DFMT_UNKNOWN == Format) {
929 } else if (Format == WINED3DFMT_DXT1) {
930 /* DXT1 is half byte per pixel */
931 Size = (mul_4w * glDesc->byte_count * mul_4h) >> 1;
933 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
934 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
935 Format == WINED3DFMT_ATI2N) {
936 Size = (mul_4w * glDesc->byte_count * mul_4h);
938 /* The pitch is a multiple of 4 bytes */
939 Size = ((Width * glDesc->byte_count) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
943 if(glDesc->heightscale != 0.0) Size *= glDesc->heightscale;
945 /** Create and initialise the surface resource **/
946 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
949 ERR("Out of memory\n");
951 return WINED3DERR_OUTOFVIDEOMEMORY;
954 /* Look at the implementation and set the correct Vtable */
958 /* Check if a 3D adapter is available when creating gl surfaces */
961 ERR("OpenGL surfaces are not available without opengl\n");
962 HeapFree(GetProcessHeap(), 0, object);
963 return WINED3DERR_NOTAVAILABLE;
965 object->lpVtbl = &IWineD3DSurface_Vtbl;
969 object->lpVtbl = &IWineGDISurface_Vtbl;
973 /* To be sure to catch this */
974 ERR("Unknown requested surface implementation %d!\n", Impl);
975 HeapFree(GetProcessHeap(), 0, object);
976 return WINED3DERR_INVALIDCALL;
979 hr = resource_init(&object->resource, WINED3DRTYPE_SURFACE, This, Size, Usage, glDesc, Pool, parent);
982 WARN("Failed to initialize resource, returning %#x\n", hr);
983 HeapFree(GetProcessHeap(), 0, object);
988 TRACE("(%p) : Created resource %p\n", This, object);
990 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
992 *ppSurface = (IWineD3DSurface *)object;
994 /* "Standalone" surface */
995 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
997 object->currentDesc.Width = Width;
998 object->currentDesc.Height = Height;
999 object->currentDesc.MultiSampleType = MultiSample;
1000 object->currentDesc.MultiSampleQuality = MultisampleQuality;
1001 object->glDescription.level = Level;
1002 list_init(&object->overlays);
1005 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
1006 object->Flags |= Discard ? SFLAG_DISCARD : 0;
1007 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
1008 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
1010 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
1012 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
1013 * this function is too deep to need to care about things like this.
1014 * Levels need to be checked too, and possibly Type since they all affect what can be done.
1015 * ****************************************/
1017 case WINED3DPOOL_SCRATCH:
1019 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
1020 "which are mutually exclusive, setting lockable to TRUE\n");
1023 case WINED3DPOOL_SYSTEMMEM:
1024 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
1025 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
1026 case WINED3DPOOL_MANAGED:
1027 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
1028 "Usage of DYNAMIC which are mutually exclusive, not doing "
1029 "anything just telling you.\n");
1031 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
1032 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
1033 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
1034 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
1037 FIXME("(%p) Unknown pool %d\n", This, Pool);
1041 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
1042 FIXME("Trying to create a render target that isn't in the default pool\n");
1045 /* mark the texture as dirty so that it gets loaded first time around*/
1046 surface_add_dirty_rect(*ppSurface, NULL);
1047 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
1048 This, Width, Height, Format, debug_d3dformat(Format),
1049 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
1051 list_init(&object->renderbuffers);
1053 /* Call the private setup routine */
1054 hr = IWineD3DSurface_PrivateSetup((IWineD3DSurface *)object);
1057 ERR("Private setup failed, returning %#x\n", hr);
1058 IWineD3DSurface_Release(*ppSurface);
1066 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
1067 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
1069 struct wined3d_rendertarget_view *object;
1071 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1074 ERR("Failed to allocate memory\n");
1075 return E_OUTOFMEMORY;
1078 object->vtbl = &wined3d_rendertarget_view_vtbl;
1079 object->refcount = 1;
1080 IWineD3DResource_AddRef(resource);
1081 object->resource = resource;
1082 object->parent = parent;
1084 *rendertarget_view = (IWineD3DRendertargetView *)object;
1089 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
1090 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1091 IWineD3DTexture **ppTexture, HANDLE *pSharedHandle, IUnknown *parent)
1093 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1094 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
1095 IWineD3DTextureImpl *object;
1100 unsigned int pow2Width;
1101 unsigned int pow2Height;
1103 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1104 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
1105 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
1107 /* TODO: It should only be possible to create textures for formats
1108 that are reported as supported */
1109 if (WINED3DFMT_UNKNOWN >= Format) {
1110 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1111 return WINED3DERR_INVALIDCALL;
1114 /* Non-power2 support */
1115 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO))
1118 pow2Height = Height;
1122 /* Find the nearest pow2 match */
1123 pow2Width = pow2Height = 1;
1124 while (pow2Width < Width) pow2Width <<= 1;
1125 while (pow2Height < Height) pow2Height <<= 1;
1127 if (pow2Width != Width || pow2Height != Height)
1131 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
1132 return WINED3DERR_INVALIDCALL;
1138 /* Calculate levels for mip mapping */
1139 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1141 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1143 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1144 return WINED3DERR_INVALIDCALL;
1149 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1150 return WINED3DERR_INVALIDCALL;
1157 Levels = wined3d_log2i(max(Width, Height)) + 1;
1158 TRACE("Calculated levels = %d\n", Levels);
1161 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1164 ERR("Out of memory\n");
1166 return WINED3DERR_OUTOFVIDEOMEMORY;
1169 object->lpVtbl = &IWineD3DTexture_Vtbl;
1170 hr = resource_init(&object->resource, WINED3DRTYPE_TEXTURE, This, 0, Usage, format_desc, Pool, parent);
1173 WARN("Failed to initialize resource, returning %#x\n", hr);
1174 HeapFree(GetProcessHeap(), 0, object);
1179 TRACE("(%p) : Created resource %p\n", This, object);
1181 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1183 *ppTexture = (IWineD3DTexture *)object;
1185 basetexture_init(&object->baseTexture, Levels, Usage);
1187 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
1189 object->baseTexture.minMipLookup = minMipLookup;
1190 object->baseTexture.magLookup = magLookup;
1192 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1193 object->baseTexture.magLookup = magLookup_noFilter;
1196 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1197 /* Precalculated scaling for 'faked' non power of two texture coords.
1198 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
1199 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
1200 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
1202 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (Width != pow2Width || Height != pow2Height)) {
1203 object->baseTexture.pow2Matrix[0] = 1.0;
1204 object->baseTexture.pow2Matrix[5] = 1.0;
1205 object->baseTexture.pow2Matrix[10] = 1.0;
1206 object->baseTexture.pow2Matrix[15] = 1.0;
1207 object->target = GL_TEXTURE_2D;
1208 object->cond_np2 = TRUE;
1209 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1210 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
1211 (Width != pow2Width || Height != pow2Height) &&
1212 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
1214 if ((Width != 1) || (Height != 1)) {
1215 object->baseTexture.pow2Matrix_identity = FALSE;
1218 object->baseTexture.pow2Matrix[0] = (float)Width;
1219 object->baseTexture.pow2Matrix[5] = (float)Height;
1220 object->baseTexture.pow2Matrix[10] = 1.0;
1221 object->baseTexture.pow2Matrix[15] = 1.0;
1222 object->target = GL_TEXTURE_RECTANGLE_ARB;
1223 object->cond_np2 = TRUE;
1224 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1226 if ((Width != pow2Width) || (Height != pow2Height)) {
1227 object->baseTexture.pow2Matrix_identity = FALSE;
1228 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
1229 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
1231 object->baseTexture.pow2Matrix[0] = 1.0;
1232 object->baseTexture.pow2Matrix[5] = 1.0;
1235 object->baseTexture.pow2Matrix[10] = 1.0;
1236 object->baseTexture.pow2Matrix[15] = 1.0;
1237 object->target = GL_TEXTURE_2D;
1238 object->cond_np2 = FALSE;
1240 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
1242 /* Generate all the surfaces */
1245 for (i = 0; i < object->baseTexture.levels; i++)
1247 /* use the callback to create the texture surface */
1248 hr = IWineD3DDeviceParent_CreateSurface(This->device_parent, parent, tmpW, tmpH, Format,
1249 Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i]);
1250 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
1251 FIXME("Failed to create surface %p\n", object);
1253 object->surfaces[i] = NULL;
1254 IWineD3DTexture_Release((IWineD3DTexture *)object);
1260 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
1261 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
1262 surface_set_texture_target(object->surfaces[i], object->target);
1263 /* calculate the next mipmap level */
1264 tmpW = max(1, tmpW >> 1);
1265 tmpH = max(1, tmpH >> 1);
1267 object->baseTexture.internal_preload = texture_internal_preload;
1269 TRACE("(%p) : Created texture %p\n", This, object);
1273 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1274 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1275 IWineD3DVolumeTexture **ppVolumeTexture, HANDLE *pSharedHandle, IUnknown *parent)
1277 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1278 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
1279 IWineD3DVolumeTextureImpl *object;
1286 /* TODO: It should only be possible to create textures for formats
1287 that are reported as supported */
1288 if (WINED3DFMT_UNKNOWN >= Format) {
1289 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1290 return WINED3DERR_INVALIDCALL;
1292 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1293 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
1294 return WINED3DERR_INVALIDCALL;
1297 /* Calculate levels for mip mapping */
1298 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1300 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1302 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1303 return WINED3DERR_INVALIDCALL;
1308 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1309 return WINED3DERR_INVALIDCALL;
1316 Levels = wined3d_log2i(max(max(Width, Height), Depth)) + 1;
1317 TRACE("Calculated levels = %d\n", Levels);
1320 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1323 ERR("Out of memory\n");
1324 *ppVolumeTexture = NULL;
1325 return WINED3DERR_OUTOFVIDEOMEMORY;
1328 object->lpVtbl = &IWineD3DVolumeTexture_Vtbl;
1329 hr = resource_init(&object->resource, WINED3DRTYPE_VOLUMETEXTURE, This, 0, Usage, format_desc, Pool, parent);
1332 WARN("Failed to initialize resource, returning %#x\n", hr);
1333 HeapFree(GetProcessHeap(), 0, object);
1334 *ppVolumeTexture = NULL;
1338 TRACE("(%p) : Created resource %p\n", This, object);
1340 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1342 basetexture_init(&object->baseTexture, Levels, Usage);
1344 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1345 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1347 /* Is NP2 support for volumes needed? */
1348 object->baseTexture.pow2Matrix[ 0] = 1.0;
1349 object->baseTexture.pow2Matrix[ 5] = 1.0;
1350 object->baseTexture.pow2Matrix[10] = 1.0;
1351 object->baseTexture.pow2Matrix[15] = 1.0;
1353 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
1355 object->baseTexture.minMipLookup = minMipLookup;
1356 object->baseTexture.magLookup = magLookup;
1358 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1359 object->baseTexture.magLookup = magLookup_noFilter;
1362 /* Generate all the surfaces */
1367 for (i = 0; i < object->baseTexture.levels; i++)
1370 /* Create the volume */
1371 hr = IWineD3DDeviceParent_CreateVolume(This->device_parent, parent,
1372 tmpW, tmpH, tmpD, Format, Pool, Usage, &object->volumes[i]);
1374 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
1375 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
1376 *ppVolumeTexture = NULL;
1380 /* Set its container to this object */
1381 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1383 /* calculate the next mipmap level */
1384 tmpW = max(1, tmpW >> 1);
1385 tmpH = max(1, tmpH >> 1);
1386 tmpD = max(1, tmpD >> 1);
1388 object->baseTexture.internal_preload = volumetexture_internal_preload;
1390 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1391 TRACE("(%p) : Created volume texture %p\n", This, object);
1395 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1396 UINT Width, UINT Height, UINT Depth,
1398 WINED3DFORMAT Format, WINED3DPOOL Pool,
1399 IWineD3DVolume** ppVolume,
1400 HANDLE* pSharedHandle, IUnknown *parent) {
1402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1403 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1404 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &GLINFO_LOCATION);
1407 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1408 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1409 return WINED3DERR_INVALIDCALL;
1412 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1415 ERR("Out of memory\n");
1417 return WINED3DERR_OUTOFVIDEOMEMORY;
1420 object->lpVtbl = &IWineD3DVolume_Vtbl;
1421 hr = resource_init(&object->resource, WINED3DRTYPE_VOLUME, This,
1422 Width * Height * Depth * format_desc->byte_count, Usage, format_desc, Pool, parent);
1425 WARN("Failed to initialize resource, returning %#x\n", hr);
1426 HeapFree(GetProcessHeap(), 0, object);
1431 TRACE("(%p) : Created resource %p\n", This, object);
1433 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1435 *ppVolume = (IWineD3DVolume *)object;
1437 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1438 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1440 object->currentDesc.Width = Width;
1441 object->currentDesc.Height = Height;
1442 object->currentDesc.Depth = Depth;
1444 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1445 object->lockable = TRUE;
1446 object->locked = FALSE;
1447 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1448 object->dirty = TRUE;
1450 volume_add_dirty_box((IWineD3DVolume *)object, NULL);
1455 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface,
1456 UINT EdgeLength, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
1457 IWineD3DCubeTexture **ppCubeTexture, HANDLE *pSharedHandle, IUnknown *parent)
1459 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1460 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &This->adapter->gl_info);
1461 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1465 unsigned int pow2EdgeLength;
1467 /* TODO: It should only be possible to create textures for formats
1468 that are reported as supported */
1469 if (WINED3DFMT_UNKNOWN >= Format) {
1470 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1471 return WINED3DERR_INVALIDCALL;
1474 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1475 WARN("(%p) : Tried to create not supported cube texture\n", This);
1476 return WINED3DERR_INVALIDCALL;
1479 /* Calculate levels for mip mapping */
1480 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP)
1482 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP))
1484 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1485 return WINED3DERR_INVALIDCALL;
1490 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1491 return WINED3DERR_INVALIDCALL;
1498 Levels = wined3d_log2i(EdgeLength) + 1;
1499 TRACE("Calculated levels = %d\n", Levels);
1502 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1505 ERR("Out of memory\n");
1506 *ppCubeTexture = NULL;
1507 return WINED3DERR_OUTOFVIDEOMEMORY;
1510 object->lpVtbl = &IWineD3DCubeTexture_Vtbl;
1511 hr = resource_init(&object->resource, WINED3DRTYPE_CUBETEXTURE, This, 0, Usage, format_desc, Pool, parent);
1514 WARN("Failed to initialize resource, returning %#x\n", hr);
1515 HeapFree(GetProcessHeap(), 0, object);
1516 *ppCubeTexture = NULL;
1520 TRACE("(%p) : Created resource %p\n", This, object);
1522 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object);
1524 basetexture_init(&object->baseTexture, Levels, Usage);
1526 TRACE("(%p) Create Cube Texture\n", This);
1528 /* Find the nearest pow2 match */
1530 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1532 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || (EdgeLength == pow2EdgeLength)) {
1533 /* Precalculated scaling for 'faked' non power of two texture coords */
1534 object->baseTexture.pow2Matrix[ 0] = 1.0;
1535 object->baseTexture.pow2Matrix[ 5] = 1.0;
1536 object->baseTexture.pow2Matrix[10] = 1.0;
1537 object->baseTexture.pow2Matrix[15] = 1.0;
1539 /* Precalculated scaling for 'faked' non power of two texture coords */
1540 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1541 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1542 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1543 object->baseTexture.pow2Matrix[15] = 1.0;
1544 object->baseTexture.pow2Matrix_identity = FALSE;
1547 if (object->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING)
1549 object->baseTexture.minMipLookup = minMipLookup;
1550 object->baseTexture.magLookup = magLookup;
1552 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1553 object->baseTexture.magLookup = magLookup_noFilter;
1556 /* Generate all the surfaces */
1558 for (i = 0; i < object->baseTexture.levels; i++) {
1560 /* Create the 6 faces */
1561 for (j = 0; j < 6; j++) {
1562 static const GLenum cube_targets[6] = {
1563 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
1564 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
1565 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
1566 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
1567 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
1568 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
1571 hr = IWineD3DDeviceParent_CreateSurface(This->device_parent, parent, tmpW, tmpW,
1572 Format, Usage, Pool, i /* Level */, j, &object->surfaces[j][i]);
1575 FIXME("(%p) Failed to create surface\n",object);
1576 IWineD3DCubeTexture_Release((IWineD3DCubeTexture *)object);
1577 *ppCubeTexture = NULL;
1580 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1581 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1582 surface_set_texture_target(object->surfaces[j][i], cube_targets[j]);
1584 tmpW = max(1, tmpW >> 1);
1586 object->baseTexture.internal_preload = cubetexture_internal_preload;
1588 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1589 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1593 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1594 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1595 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1596 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1597 const IWineD3DQueryVtbl *vtable;
1599 /* Just a check to see if we support this type of query */
1601 case WINED3DQUERYTYPE_OCCLUSION:
1602 TRACE("(%p) occlusion query\n", This);
1603 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1606 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1608 vtable = &IWineD3DOcclusionQuery_Vtbl;
1611 case WINED3DQUERYTYPE_EVENT:
1612 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1613 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1614 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1616 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1618 vtable = &IWineD3DEventQuery_Vtbl;
1622 case WINED3DQUERYTYPE_VCACHE:
1623 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1624 case WINED3DQUERYTYPE_VERTEXSTATS:
1625 case WINED3DQUERYTYPE_TIMESTAMP:
1626 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1627 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1628 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1629 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1630 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1631 case WINED3DQUERYTYPE_PIXELTIMINGS:
1632 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1633 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1635 /* Use the base Query vtable until we have a special one for each query */
1636 vtable = &IWineD3DQuery_Vtbl;
1637 FIXME("(%p) Unhandled query type %d\n", This, Type);
1639 if(NULL == ppQuery || hr != WINED3D_OK) {
1643 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1646 ERR("Out of memory\n");
1648 return WINED3DERR_OUTOFVIDEOMEMORY;
1651 object->lpVtbl = vtable;
1652 object->type = Type;
1653 object->state = QUERY_CREATED;
1654 object->wineD3DDevice = This;
1655 object->parent = parent;
1658 *ppQuery = (IWineD3DQuery *)object;
1660 /* allocated the 'extended' data based on the type of query requested */
1662 case WINED3DQUERYTYPE_OCCLUSION:
1663 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1664 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1666 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1667 TRACE("(%p) Allocating data for an occlusion query\n", This);
1669 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1671 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1675 case WINED3DQUERYTYPE_EVENT:
1676 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1677 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1679 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1681 if(GL_SUPPORT(APPLE_FENCE)) {
1682 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1683 checkGLcall("glGenFencesAPPLE");
1684 } else if(GL_SUPPORT(NV_FENCE)) {
1685 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1686 checkGLcall("glGenFencesNV");
1691 case WINED3DQUERYTYPE_VCACHE:
1692 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1693 case WINED3DQUERYTYPE_VERTEXSTATS:
1694 case WINED3DQUERYTYPE_TIMESTAMP:
1695 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1696 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1697 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1698 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1699 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1700 case WINED3DQUERYTYPE_PIXELTIMINGS:
1701 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1702 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1704 object->extendedData = 0;
1705 FIXME("(%p) Unhandled query type %d\n",This , Type);
1707 TRACE("(%p) : Created Query %p\n", This, object);
1711 /*****************************************************************************
1712 * IWineD3DDeviceImpl_SetupFullscreenWindow
1714 * Helper function that modifies a HWND's Style and ExStyle for proper
1718 * iface: Pointer to the IWineD3DDevice interface
1719 * window: Window to setup
1721 *****************************************************************************/
1722 static LONG fullscreen_style(LONG orig_style) {
1723 LONG style = orig_style;
1724 style &= ~WS_CAPTION;
1725 style &= ~WS_THICKFRAME;
1727 /* Make sure the window is managed, otherwise we won't get keyboard input */
1728 style |= WS_POPUP | WS_SYSMENU;
1733 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1734 LONG exStyle = orig_exStyle;
1736 /* Filter out window decorations */
1737 exStyle &= ~WS_EX_WINDOWEDGE;
1738 exStyle &= ~WS_EX_CLIENTEDGE;
1743 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1746 LONG style, exStyle;
1747 /* Don't do anything if an original style is stored.
1748 * That shouldn't happen
1750 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1751 if (This->style || This->exStyle) {
1752 ERR("(%p): Want to change the window parameters of HWND %p, but "
1753 "another style is stored for restoration afterwards\n", This, window);
1756 /* Get the parameters and save them */
1757 style = GetWindowLongW(window, GWL_STYLE);
1758 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1759 This->style = style;
1760 This->exStyle = exStyle;
1762 style = fullscreen_style(style);
1763 exStyle = fullscreen_exStyle(exStyle);
1765 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1766 This->style, This->exStyle, style, exStyle);
1768 SetWindowLongW(window, GWL_STYLE, style);
1769 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1771 /* Inform the window about the update. */
1772 SetWindowPos(window, HWND_TOP, 0, 0,
1773 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1776 /*****************************************************************************
1777 * IWineD3DDeviceImpl_RestoreWindow
1779 * Helper function that restores a windows' properties when taking it out
1780 * of fullscreen mode
1783 * iface: Pointer to the IWineD3DDevice interface
1784 * window: Window to setup
1786 *****************************************************************************/
1787 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1788 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1789 LONG style, exStyle;
1791 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1792 * switch, do nothing
1794 if (!This->style && !This->exStyle) return;
1796 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1797 This, window, This->style, This->exStyle);
1799 style = GetWindowLongW(window, GWL_STYLE);
1800 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1802 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1803 * Some applications change it before calling Reset() when switching between windowed and
1804 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1806 if(style == fullscreen_style(This->style) &&
1807 exStyle == fullscreen_style(This->exStyle)) {
1808 SetWindowLongW(window, GWL_STYLE, This->style);
1809 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1812 /* Delete the old values */
1816 /* Inform the window about the update */
1817 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1818 0, 0, 0, 0, /* Pos, Size, ignored */
1819 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1822 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1823 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1824 WINED3DPRESENT_PARAMETERS *pPresentationParameters, IWineD3DSwapChain **ppSwapChain,
1825 IUnknown *parent, WINED3DSURFTYPE surface_type)
1827 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1830 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1832 IUnknown *bufferParent;
1833 BOOL displaymode_set = FALSE;
1834 WINED3DDISPLAYMODE Mode;
1835 const struct GlPixelFormatDesc *format_desc;
1837 TRACE("(%p) : Created Additional Swap Chain\n", This);
1839 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1840 * does a device hold a reference to a swap chain giving them a lifetime of the device
1841 * or does the swap chain notify the device of its destruction.
1842 *******************************/
1844 /* Check the params */
1845 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1846 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1847 return WINED3DERR_INVALIDCALL;
1848 } else if (pPresentationParameters->BackBufferCount > 1) {
1849 FIXME("The app requests more than one back buffer, this can't be supported properly. Please configure the application to use double buffering(=1 back buffer) if possible\n");
1852 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1855 ERR("Out of memory\n");
1856 *ppSwapChain = NULL;
1857 return WINED3DERR_OUTOFVIDEOMEMORY;
1860 switch(surface_type) {
1862 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1864 case SURFACE_OPENGL:
1865 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1867 case SURFACE_UNKNOWN:
1868 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1869 HeapFree(GetProcessHeap(), 0, object);
1870 return WINED3DERR_INVALIDCALL;
1872 object->wineD3DDevice = This;
1873 object->parent = parent;
1876 *ppSwapChain = (IWineD3DSwapChain *)object;
1878 /*********************
1879 * Lookup the window Handle and the relating X window handle
1880 ********************/
1882 /* Setup hwnd we are using, plus which display this equates to */
1883 object->win_handle = pPresentationParameters->hDeviceWindow;
1884 if (!object->win_handle) {
1885 object->win_handle = This->createParms.hFocusWindow;
1887 if(!pPresentationParameters->Windowed && object->win_handle) {
1888 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1889 pPresentationParameters->BackBufferWidth,
1890 pPresentationParameters->BackBufferHeight);
1893 hDc = GetDC(object->win_handle);
1894 TRACE("Using hDc %p\n", hDc);
1897 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1898 return WINED3DERR_NOTAVAILABLE;
1901 /* Get info on the current display setup */
1902 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1903 object->orig_width = Mode.Width;
1904 object->orig_height = Mode.Height;
1905 object->orig_fmt = Mode.Format;
1906 format_desc = getFormatDescEntry(Mode.Format, &GLINFO_LOCATION);
1908 if (pPresentationParameters->Windowed &&
1909 ((pPresentationParameters->BackBufferWidth == 0) ||
1910 (pPresentationParameters->BackBufferHeight == 0) ||
1911 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1914 GetClientRect(object->win_handle, &Rect);
1916 if (pPresentationParameters->BackBufferWidth == 0) {
1917 pPresentationParameters->BackBufferWidth = Rect.right;
1918 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1920 if (pPresentationParameters->BackBufferHeight == 0) {
1921 pPresentationParameters->BackBufferHeight = Rect.bottom;
1922 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1924 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1925 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1926 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1930 /* Put the correct figures in the presentation parameters */
1931 TRACE("Copying across presentation parameters\n");
1932 object->presentParms = *pPresentationParameters;
1934 TRACE("calling rendertarget CB\n");
1935 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1936 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1937 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1938 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->frontBuffer);
1939 if (SUCCEEDED(hr)) {
1940 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1941 ((IWineD3DSurfaceImpl *)object->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
1942 if(surface_type == SURFACE_OPENGL) {
1943 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1946 ERR("Failed to create the front buffer\n");
1950 /*********************
1951 * Windowed / Fullscreen
1952 *******************/
1955 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1956 * so we should really check to see if there is a fullscreen swapchain already
1957 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1958 **************************************/
1960 if (!pPresentationParameters->Windowed) {
1961 WINED3DDISPLAYMODE mode;
1964 /* Change the display settings */
1965 mode.Width = pPresentationParameters->BackBufferWidth;
1966 mode.Height = pPresentationParameters->BackBufferHeight;
1967 mode.Format = pPresentationParameters->BackBufferFormat;
1968 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1970 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1971 displaymode_set = TRUE;
1975 * Create an opengl context for the display visual
1976 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1977 * use different properties after that point in time. FIXME: How to handle when requested format
1978 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1979 * it chooses is identical to the one already being used!
1980 **********************************/
1981 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1983 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1984 if(!object->context) {
1985 ERR("Failed to create the context array\n");
1989 object->num_contexts = 1;
1991 if(surface_type == SURFACE_OPENGL) {
1992 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1993 if (!object->context[0]) {
1994 ERR("Failed to create a new context\n");
1995 hr = WINED3DERR_NOTAVAILABLE;
1998 TRACE("Context created (HWND=%p, glContext=%p)\n",
1999 object->win_handle, object->context[0]->glCtx);
2003 /*********************
2004 * Create the back, front and stencil buffers
2005 *******************/
2006 if(object->presentParms.BackBufferCount > 0) {
2009 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
2010 if(!object->backBuffer) {
2011 ERR("Out of memory\n");
2016 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
2017 TRACE("calling rendertarget CB\n");
2018 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
2019 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
2020 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
2021 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->backBuffer[i]);
2023 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
2024 ((IWineD3DSurfaceImpl *)object->backBuffer[i])->Flags |= SFLAG_SWAPCHAIN;
2026 ERR("Cannot create new back buffer\n");
2029 if(surface_type == SURFACE_OPENGL) {
2031 glDrawBuffer(GL_BACK);
2032 checkGLcall("glDrawBuffer(GL_BACK)");
2037 object->backBuffer = NULL;
2039 /* Single buffering - draw to front buffer */
2040 if(surface_type == SURFACE_OPENGL) {
2042 glDrawBuffer(GL_FRONT);
2043 checkGLcall("glDrawBuffer(GL_FRONT)");
2048 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
2049 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
2050 TRACE("Creating depth stencil buffer\n");
2051 if (This->auto_depth_stencil_buffer == NULL ) {
2052 hr = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent, parent,
2053 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
2054 object->presentParms.AutoDepthStencilFormat, object->presentParms.MultiSampleType,
2055 object->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */,
2056 &This->auto_depth_stencil_buffer);
2057 if (SUCCEEDED(hr)) {
2058 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
2060 ERR("Failed to create the auto depth stencil\n");
2066 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
2068 TRACE("Created swapchain %p\n", object);
2069 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
2073 if (displaymode_set) {
2077 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
2080 /* Change the display settings */
2081 memset(&devmode, 0, sizeof(devmode));
2082 devmode.dmSize = sizeof(devmode);
2083 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2084 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2085 devmode.dmPelsWidth = object->orig_width;
2086 devmode.dmPelsHeight = object->orig_height;
2087 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
2090 if (object->backBuffer) {
2092 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
2093 if(object->backBuffer[i]) {
2094 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
2095 IUnknown_Release(bufferParent); /* once for the get parent */
2096 if (IUnknown_Release(bufferParent) > 0) {
2097 FIXME("(%p) Something's still holding the back buffer\n",This);
2101 HeapFree(GetProcessHeap(), 0, object->backBuffer);
2102 object->backBuffer = NULL;
2104 if(object->context && object->context[0])
2105 DestroyContext(This, object->context[0]);
2106 if(object->frontBuffer) {
2107 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
2108 IUnknown_Release(bufferParent); /* once for the get parent */
2109 if (IUnknown_Release(bufferParent) > 0) {
2110 FIXME("(%p) Something's still holding the front buffer\n",This);
2113 HeapFree(GetProcessHeap(), 0, object);
2117 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
2118 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
2119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2120 TRACE("(%p)\n", This);
2122 return This->NumberOfSwapChains;
2125 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
2126 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2127 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
2129 if(iSwapChain < This->NumberOfSwapChains) {
2130 *pSwapChain = This->swapchains[iSwapChain];
2131 IWineD3DSwapChain_AddRef(*pSwapChain);
2132 TRACE("(%p) returning %p\n", This, *pSwapChain);
2135 TRACE("Swapchain out of range\n");
2137 return WINED3DERR_INVALIDCALL;
2142 * Vertex Declaration
2144 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
2145 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
2146 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2147 IWineD3DVertexDeclarationImpl *object = NULL;
2148 HRESULT hr = WINED3D_OK;
2150 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
2151 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
2153 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2156 ERR("Out of memory\n");
2157 *ppVertexDeclaration = NULL;
2158 return WINED3DERR_OUTOFVIDEOMEMORY;
2161 object->lpVtbl = &IWineD3DVertexDeclaration_Vtbl;
2162 object->wineD3DDevice = This;
2163 object->parent = parent;
2166 *ppVertexDeclaration = (IWineD3DVertexDeclaration *)object;
2168 hr = vertexdeclaration_init(object, elements, element_count);
2171 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
2172 *ppVertexDeclaration = NULL;
2178 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
2179 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
2181 unsigned int idx, idx2;
2182 unsigned int offset;
2183 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
2184 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
2185 BOOL has_blend_idx = has_blend &&
2186 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
2187 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
2188 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
2189 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
2190 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
2191 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
2192 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
2194 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
2195 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
2196 WINED3DVERTEXELEMENT *elements = NULL;
2199 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
2200 if (has_blend_idx) num_blends--;
2202 /* Compute declaration size */
2203 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
2204 has_psize + has_diffuse + has_specular + num_textures;
2206 /* convert the declaration */
2207 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
2208 if (!elements) return ~0U;
2212 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
2213 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
2214 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
2216 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
2217 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
2218 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
2221 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
2222 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
2224 elements[idx].usage_idx = 0;
2227 if (has_blend && (num_blends > 0)) {
2228 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
2229 elements[idx].format = WINED3DFMT_A8R8G8B8;
2231 switch(num_blends) {
2232 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
2233 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
2234 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
2235 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
2237 ERR("Unexpected amount of blend values: %u\n", num_blends);
2240 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
2241 elements[idx].usage_idx = 0;
2244 if (has_blend_idx) {
2245 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
2246 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
2247 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
2248 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
2249 elements[idx].format = WINED3DFMT_A8R8G8B8;
2251 elements[idx].format = WINED3DFMT_R32_FLOAT;
2252 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
2253 elements[idx].usage_idx = 0;
2257 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
2258 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
2259 elements[idx].usage_idx = 0;
2263 elements[idx].format = WINED3DFMT_R32_FLOAT;
2264 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
2265 elements[idx].usage_idx = 0;
2269 elements[idx].format = WINED3DFMT_A8R8G8B8;
2270 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
2271 elements[idx].usage_idx = 0;
2275 elements[idx].format = WINED3DFMT_A8R8G8B8;
2276 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
2277 elements[idx].usage_idx = 1;
2280 for (idx2 = 0; idx2 < num_textures; idx2++) {
2281 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
2282 switch (numcoords) {
2283 case WINED3DFVF_TEXTUREFORMAT1:
2284 elements[idx].format = WINED3DFMT_R32_FLOAT;
2286 case WINED3DFVF_TEXTUREFORMAT2:
2287 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
2289 case WINED3DFVF_TEXTUREFORMAT3:
2290 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
2292 case WINED3DFVF_TEXTUREFORMAT4:
2293 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
2296 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
2297 elements[idx].usage_idx = idx2;
2301 /* Now compute offsets, and initialize the rest of the fields */
2302 for (idx = 0, offset = 0; idx < size; ++idx)
2304 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
2305 elements[idx].input_slot = 0;
2306 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
2307 elements[idx].offset = offset;
2308 offset += format_desc->component_count * format_desc->component_size;
2311 *ppVertexElements = elements;
2315 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
2316 WINED3DVERTEXELEMENT* elements = NULL;
2317 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2321 size = ConvertFvfToDeclaration(This, Fvf, &elements);
2322 if (size == ~0U) return WINED3DERR_OUTOFVIDEOMEMORY;
2324 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
2325 HeapFree(GetProcessHeap(), 0, elements);
2326 if (hr != S_OK) return hr;
2331 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
2332 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2333 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
2334 HRESULT hr = WINED3D_OK;
2336 if (!pFunction) return WINED3DERR_INVALIDCALL;
2338 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2341 ERR("Out of memory\n");
2342 *ppVertexShader = NULL;
2343 return WINED3DERR_OUTOFVIDEOMEMORY;
2346 object->lpVtbl = &IWineD3DVertexShader_Vtbl;
2347 object->parent = parent;
2348 shader_init(&object->baseShader, iface, IWineD3DVertexShaderImpl_shader_ins);
2349 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2350 *ppVertexShader = (IWineD3DVertexShader *)object;
2352 TRACE("(%p) : Created vertex shader %p\n", This, *ppVertexShader);
2354 if (vertex_declaration) {
2355 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
2358 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
2361 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2362 IWineD3DVertexShader_Release(*ppVertexShader);
2363 *ppVertexShader = NULL;
2370 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
2371 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2372 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
2373 HRESULT hr = WINED3D_OK;
2375 if (!pFunction) return WINED3DERR_INVALIDCALL;
2377 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2380 ERR("Out of memory\n");
2381 *ppPixelShader = NULL;
2382 return WINED3DERR_OUTOFVIDEOMEMORY;
2385 object->lpVtbl = &IWineD3DPixelShader_Vtbl;
2386 object->parent = parent;
2387 shader_init(&object->baseShader, iface, IWineD3DPixelShaderImpl_shader_ins);
2388 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
2389 *ppPixelShader = (IWineD3DPixelShader *)object;
2391 TRACE("(%p) : Created pixel shader %p\n", This, *ppPixelShader);
2393 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
2396 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
2397 IWineD3DPixelShader_Release(*ppPixelShader);
2398 *ppPixelShader = NULL;
2405 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
2406 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
2408 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2409 IWineD3DPaletteImpl *object;
2411 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
2413 /* Create the new object */
2414 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
2416 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
2417 return E_OUTOFMEMORY;
2420 object->lpVtbl = &IWineD3DPalette_Vtbl;
2422 object->Flags = Flags;
2423 object->parent = Parent;
2424 object->wineD3DDevice = This;
2425 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
2426 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
2429 HeapFree( GetProcessHeap(), 0, object);
2430 return E_OUTOFMEMORY;
2433 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
2435 IWineD3DPalette_Release((IWineD3DPalette *) object);
2439 *Palette = (IWineD3DPalette *) object;
2444 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
2448 HDC dcb = NULL, dcs = NULL;
2449 WINEDDCOLORKEY colorkey;
2451 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
2454 GetObjectA(hbm, sizeof(BITMAP), &bm);
2455 dcb = CreateCompatibleDC(NULL);
2457 SelectObject(dcb, hbm);
2461 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
2462 * couldn't be loaded
2464 memset(&bm, 0, sizeof(bm));
2469 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
2470 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
2471 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
2473 ERR("Wine logo requested, but failed to create surface\n");
2478 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
2479 if(FAILED(hr)) goto out;
2480 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
2481 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
2483 colorkey.dwColorSpaceLowValue = 0;
2484 colorkey.dwColorSpaceHighValue = 0;
2485 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2487 /* Fill the surface with a white color to show that wined3d is there */
2488 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2501 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2503 /* Under DirectX you can have texture stage operations even if no texture is
2504 bound, whereas opengl will only do texture operations when a valid texture is
2505 bound. We emulate this by creating dummy textures and binding them to each
2506 texture stage, but disable all stages by default. Hence if a stage is enabled
2507 then the default texture will kick in until replaced by a SetTexture call */
2510 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2511 /* The dummy texture does not have client storage backing */
2512 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2513 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2515 for (i = 0; i < GL_LIMITS(textures); i++) {
2516 GLubyte white = 255;
2518 /* Make appropriate texture active */
2519 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2520 checkGLcall("glActiveTextureARB");
2522 /* Generate an opengl texture name */
2523 glGenTextures(1, &This->dummyTextureName[i]);
2524 checkGLcall("glGenTextures");
2525 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2527 /* Generate a dummy 2d texture (not using 1d because they cause many
2528 * DRI drivers fall back to sw) */
2529 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2530 checkGLcall("glBindTexture");
2532 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2533 checkGLcall("glTexImage2D");
2535 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2536 /* Reenable because if supported it is enabled by default */
2537 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2538 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2544 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
2545 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2547 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2548 IWineD3DSwapChainImpl *swapchain = NULL;
2553 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
2555 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2556 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2558 /* TODO: Test if OpenGL is compiled in and loaded */
2560 TRACE("(%p) : Creating stateblock\n", This);
2561 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2562 hr = IWineD3DDevice_CreateStateBlock(iface,
2564 (IWineD3DStateBlock **)&This->stateBlock,
2566 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2567 WARN("Failed to create stateblock\n");
2570 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2571 This->updateStateBlock = This->stateBlock;
2572 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2574 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2575 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2577 This->NumberOfPalettes = 1;
2578 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2579 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2580 ERR("Out of memory!\n");
2583 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2584 if(!This->palettes[0]) {
2585 ERR("Out of memory!\n");
2588 for (i = 0; i < 256; ++i) {
2589 This->palettes[0][i].peRed = 0xFF;
2590 This->palettes[0][i].peGreen = 0xFF;
2591 This->palettes[0][i].peBlue = 0xFF;
2592 This->palettes[0][i].peFlags = 0xFF;
2594 This->currentPalette = 0;
2596 /* Initialize the texture unit mapping to a 1:1 mapping */
2597 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2598 if (state < GL_LIMITS(fragment_samplers)) {
2599 This->texUnitMap[state] = state;
2600 This->rev_tex_unit_map[state] = state;
2602 This->texUnitMap[state] = -1;
2603 This->rev_tex_unit_map[state] = -1;
2607 /* Setup the implicit swapchain */
2608 TRACE("Creating implicit swapchain\n");
2609 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2610 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2613 WARN("Failed to create implicit swapchain\n");
2617 This->NumberOfSwapChains = 1;
2618 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2619 if(!This->swapchains) {
2620 ERR("Out of memory!\n");
2623 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2625 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2626 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2627 This->render_targets[0] = swapchain->backBuffer[0];
2628 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2631 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2632 This->render_targets[0] = swapchain->frontBuffer;
2633 This->lastActiveRenderTarget = swapchain->frontBuffer;
2635 IWineD3DSurface_AddRef(This->render_targets[0]);
2636 This->activeContext = swapchain->context[0];
2637 This->lastThread = GetCurrentThreadId();
2639 /* Depth Stencil support */
2640 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2641 if (NULL != This->stencilBufferTarget) {
2642 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2645 hr = This->shader_backend->shader_alloc_private(iface);
2647 TRACE("Shader private data couldn't be allocated\n");
2650 hr = This->frag_pipe->alloc_private(iface);
2652 TRACE("Fragment pipeline private data couldn't be allocated\n");
2655 hr = This->blitter->alloc_private(iface);
2657 TRACE("Blitter private data couldn't be allocated\n");
2661 /* Set up some starting GL setup */
2663 /* Setup all the devices defaults */
2664 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2665 create_dummy_textures(This);
2669 /* Initialize the current view state */
2670 This->view_ident = 1;
2671 This->contexts[0]->last_was_rhw = 0;
2672 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2673 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2675 switch(wined3d_settings.offscreen_rendering_mode) {
2678 This->offscreenBuffer = GL_BACK;
2681 case ORM_BACKBUFFER:
2683 if(This->activeContext->aux_buffers > 0) {
2684 TRACE("Using auxilliary buffer for offscreen rendering\n");
2685 This->offscreenBuffer = GL_AUX0;
2687 TRACE("Using back buffer for offscreen rendering\n");
2688 This->offscreenBuffer = GL_BACK;
2693 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2696 /* Clear the screen */
2697 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2698 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2701 This->d3d_initialized = TRUE;
2703 if(wined3d_settings.logo) {
2704 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2706 This->highest_dirty_ps_const = 0;
2707 This->highest_dirty_vs_const = 0;
2711 HeapFree(GetProcessHeap(), 0, This->render_targets);
2712 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2713 HeapFree(GetProcessHeap(), 0, This->swapchains);
2714 This->NumberOfSwapChains = 0;
2715 if(This->palettes) {
2716 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2717 HeapFree(GetProcessHeap(), 0, This->palettes);
2719 This->NumberOfPalettes = 0;
2721 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2723 if(This->stateBlock) {
2724 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2725 This->stateBlock = NULL;
2727 if (This->blit_priv) {
2728 This->blitter->free_private(iface);
2730 if (This->fragment_priv) {
2731 This->frag_pipe->free_private(iface);
2733 if (This->shader_priv) {
2734 This->shader_backend->shader_free_private(iface);
2739 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2740 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2742 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2743 IWineD3DSwapChainImpl *swapchain = NULL;
2746 /* Setup the implicit swapchain */
2747 TRACE("Creating implicit swapchain\n");
2748 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2749 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2752 WARN("Failed to create implicit swapchain\n");
2756 This->NumberOfSwapChains = 1;
2757 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2758 if(!This->swapchains) {
2759 ERR("Out of memory!\n");
2762 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2766 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2770 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2772 IWineD3DResource_UnLoad(resource);
2773 IWineD3DResource_Release(resource);
2777 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2778 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2781 TRACE("(%p)\n", This);
2783 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2785 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2786 * it was created. Thus make sure a context is active for the glDelete* calls
2788 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2790 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2792 /* Unload resources */
2793 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2795 TRACE("Deleting high order patches\n");
2796 for(i = 0; i < PATCHMAP_SIZE; i++) {
2797 struct list *e1, *e2;
2798 struct WineD3DRectPatch *patch;
2799 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2800 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2801 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2805 /* Delete the palette conversion shader if it is around */
2806 if(This->paletteConversionShader) {
2808 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2810 This->paletteConversionShader = 0;
2813 /* Delete the pbuffer context if there is any */
2814 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2816 /* Delete the mouse cursor texture */
2817 if(This->cursorTexture) {
2819 glDeleteTextures(1, &This->cursorTexture);
2821 This->cursorTexture = 0;
2824 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2825 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2827 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2828 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2831 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2832 * private data, it might contain opengl pointers
2834 if(This->depth_blt_texture) {
2835 glDeleteTextures(1, &This->depth_blt_texture);
2836 This->depth_blt_texture = 0;
2838 if (This->depth_blt_rb) {
2839 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2840 This->depth_blt_rb = 0;
2841 This->depth_blt_rb_w = 0;
2842 This->depth_blt_rb_h = 0;
2845 /* Release the update stateblock */
2846 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2847 if(This->updateStateBlock != This->stateBlock)
2848 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2850 This->updateStateBlock = NULL;
2852 { /* because were not doing proper internal refcounts releasing the primary state block
2853 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2854 to set this->stateBlock = NULL; first */
2855 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2856 This->stateBlock = NULL;
2858 /* Release the stateblock */
2859 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2860 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2864 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2865 This->blitter->free_private(iface);
2866 This->frag_pipe->free_private(iface);
2867 This->shader_backend->shader_free_private(iface);
2869 /* Release the buffers (with sanity checks)*/
2870 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2871 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2872 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2873 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2875 This->stencilBufferTarget = NULL;
2877 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2878 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2879 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2881 TRACE("Setting rendertarget to NULL\n");
2882 This->render_targets[0] = NULL;
2884 if (This->auto_depth_stencil_buffer) {
2885 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2886 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2888 This->auto_depth_stencil_buffer = NULL;
2891 for(i=0; i < This->NumberOfSwapChains; i++) {
2892 TRACE("Releasing the implicit swapchain %d\n", i);
2893 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2894 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2898 HeapFree(GetProcessHeap(), 0, This->swapchains);
2899 This->swapchains = NULL;
2900 This->NumberOfSwapChains = 0;
2902 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2903 HeapFree(GetProcessHeap(), 0, This->palettes);
2904 This->palettes = NULL;
2905 This->NumberOfPalettes = 0;
2907 HeapFree(GetProcessHeap(), 0, This->render_targets);
2908 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2909 This->render_targets = NULL;
2910 This->draw_buffers = NULL;
2912 This->d3d_initialized = FALSE;
2916 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2917 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2920 for(i=0; i < This->NumberOfSwapChains; i++) {
2921 TRACE("Releasing the implicit swapchain %d\n", i);
2922 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2923 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2927 HeapFree(GetProcessHeap(), 0, This->swapchains);
2928 This->swapchains = NULL;
2929 This->NumberOfSwapChains = 0;
2933 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2934 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2935 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2937 * There is no way to deactivate thread safety once it is enabled.
2939 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2940 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2942 /*For now just store the flag(needed in case of ddraw) */
2943 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2948 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2949 const WINED3DDISPLAYMODE* pMode) {
2951 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2953 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &GLINFO_LOCATION);
2956 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2958 /* Resize the screen even without a window:
2959 * The app could have unset it with SetCooperativeLevel, but not called
2960 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2961 * but we don't have any hwnd
2964 memset(&devmode, 0, sizeof(devmode));
2965 devmode.dmSize = sizeof(devmode);
2966 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2967 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2968 devmode.dmPelsWidth = pMode->Width;
2969 devmode.dmPelsHeight = pMode->Height;
2971 devmode.dmDisplayFrequency = pMode->RefreshRate;
2972 if (pMode->RefreshRate != 0) {
2973 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2976 /* Only change the mode if necessary */
2977 if( (This->ddraw_width == pMode->Width) &&
2978 (This->ddraw_height == pMode->Height) &&
2979 (This->ddraw_format == pMode->Format) &&
2980 (pMode->RefreshRate == 0) ) {
2984 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2985 if (ret != DISP_CHANGE_SUCCESSFUL) {
2986 if(devmode.dmDisplayFrequency != 0) {
2987 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2988 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2989 devmode.dmDisplayFrequency = 0;
2990 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2992 if(ret != DISP_CHANGE_SUCCESSFUL) {
2993 return WINED3DERR_NOTAVAILABLE;
2997 /* Store the new values */
2998 This->ddraw_width = pMode->Width;
2999 This->ddraw_height = pMode->Height;
3000 This->ddraw_format = pMode->Format;
3002 /* And finally clip mouse to our screen */
3003 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
3004 ClipCursor(&clip_rc);
3009 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
3010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3011 *ppD3D= This->wineD3D;
3012 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
3013 IWineD3D_AddRef(*ppD3D);
3017 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
3018 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3020 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
3021 (This->adapter->TextureRam/(1024*1024)),
3022 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
3023 /* return simulated texture memory left */
3024 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
3028 * Get / Set Stream Source
3030 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
3031 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
3033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3034 IWineD3DBuffer *oldSrc;
3036 if (StreamNumber >= MAX_STREAMS) {
3037 WARN("Stream out of range %d\n", StreamNumber);
3038 return WINED3DERR_INVALIDCALL;
3039 } else if(OffsetInBytes & 0x3) {
3040 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
3041 return WINED3DERR_INVALIDCALL;
3044 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
3045 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
3047 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
3049 if(oldSrc == pStreamData &&
3050 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
3051 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
3052 TRACE("Application is setting the old values over, nothing to do\n");
3056 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
3058 This->updateStateBlock->streamStride[StreamNumber] = Stride;
3059 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
3062 /* Handle recording of state blocks */
3063 if (This->isRecordingState) {
3064 TRACE("Recording... not performing anything\n");
3065 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
3066 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
3070 if (pStreamData != NULL) {
3071 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
3072 IWineD3DBuffer_AddRef(pStreamData);
3074 if (oldSrc != NULL) {
3075 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
3076 IWineD3DBuffer_Release(oldSrc);
3079 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3084 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
3085 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
3087 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3089 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
3090 This->stateBlock->streamSource[StreamNumber],
3091 This->stateBlock->streamOffset[StreamNumber],
3092 This->stateBlock->streamStride[StreamNumber]);
3094 if (StreamNumber >= MAX_STREAMS) {
3095 WARN("Stream out of range %d\n", StreamNumber);
3096 return WINED3DERR_INVALIDCALL;
3098 *pStream = This->stateBlock->streamSource[StreamNumber];
3099 *pStride = This->stateBlock->streamStride[StreamNumber];
3101 *pOffset = This->stateBlock->streamOffset[StreamNumber];
3104 if (*pStream != NULL) {
3105 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
3110 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
3111 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3112 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
3113 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
3115 /* Verify input at least in d3d9 this is invalid*/
3116 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
3117 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
3118 return WINED3DERR_INVALIDCALL;
3120 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
3121 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
3122 return WINED3DERR_INVALIDCALL;
3125 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
3126 return WINED3DERR_INVALIDCALL;
3129 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
3130 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
3132 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
3133 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
3135 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
3136 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
3137 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3143 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
3144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3146 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
3147 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
3149 TRACE("(%p) : returning %d\n", This, *Divider);
3155 * Get / Set & Multiply Transform
3157 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
3158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3160 /* Most of this routine, comments included copied from ddraw tree initially: */
3161 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
3163 /* Handle recording of state blocks */
3164 if (This->isRecordingState) {
3165 TRACE("Recording... not performing anything\n");
3166 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
3167 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
3172 * If the new matrix is the same as the current one,
3173 * we cut off any further processing. this seems to be a reasonable
3174 * optimization because as was noticed, some apps (warcraft3 for example)
3175 * tend towards setting the same matrix repeatedly for some reason.
3177 * From here on we assume that the new matrix is different, wherever it matters.
3179 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
3180 TRACE("The app is setting the same matrix over again\n");
3183 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
3187 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
3188 where ViewMat = Camera space, WorldMat = world space.
3190 In OpenGL, camera and world space is combined into GL_MODELVIEW
3191 matrix. The Projection matrix stay projection matrix.
3194 /* Capture the times we can just ignore the change for now */
3195 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
3196 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
3197 /* Handled by the state manager */
3200 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
3204 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
3205 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3206 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
3207 *pMatrix = This->stateBlock->transforms[State];
3211 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
3212 const WINED3DMATRIX *mat = NULL;
3215 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
3216 * below means it will be recorded in a state block change, but it
3217 * works regardless where it is recorded.
3218 * If this is found to be wrong, change to StateBlock.
3220 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3221 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
3223 if (State <= HIGHEST_TRANSFORMSTATE)
3225 mat = &This->updateStateBlock->transforms[State];
3227 FIXME("Unhandled transform state!!\n");
3230 multiply_matrix(&temp, mat, pMatrix);
3232 /* Apply change via set transform - will reapply to eg. lights this way */
3233 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
3239 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
3240 you can reference any indexes you want as long as that number max are enabled at any
3241 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
3242 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
3243 but when recording, just build a chain pretty much of commands to be replayed. */
3245 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
3247 PLIGHTINFOEL *object = NULL;
3248 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3252 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
3254 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
3258 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
3259 return WINED3DERR_INVALIDCALL;
3262 switch(pLight->Type) {
3263 case WINED3DLIGHT_POINT:
3264 case WINED3DLIGHT_SPOT:
3265 case WINED3DLIGHT_PARALLELPOINT:
3266 case WINED3DLIGHT_GLSPOT:
3267 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
3270 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
3271 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
3272 return WINED3DERR_INVALIDCALL;
3276 case WINED3DLIGHT_DIRECTIONAL:
3277 /* Ignores attenuation */
3281 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
3282 return WINED3DERR_INVALIDCALL;
3285 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3286 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3287 if(object->OriginalIndex == Index) break;
3292 TRACE("Adding new light\n");
3293 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
3295 ERR("Out of memory error when allocating a light\n");
3296 return E_OUTOFMEMORY;
3298 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
3299 object->glIndex = -1;
3300 object->OriginalIndex = Index;
3301 object->changed = TRUE;
3304 /* Initialize the object */
3305 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,
3306 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
3307 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
3308 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
3309 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
3310 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
3311 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
3313 /* Save away the information */
3314 object->OriginalParms = *pLight;
3316 switch (pLight->Type) {
3317 case WINED3DLIGHT_POINT:
3319 object->lightPosn[0] = pLight->Position.x;
3320 object->lightPosn[1] = pLight->Position.y;
3321 object->lightPosn[2] = pLight->Position.z;
3322 object->lightPosn[3] = 1.0f;
3323 object->cutoff = 180.0f;
3327 case WINED3DLIGHT_DIRECTIONAL:
3329 object->lightPosn[0] = -pLight->Direction.x;
3330 object->lightPosn[1] = -pLight->Direction.y;
3331 object->lightPosn[2] = -pLight->Direction.z;
3332 object->lightPosn[3] = 0.0;
3333 object->exponent = 0.0f;
3334 object->cutoff = 180.0f;
3337 case WINED3DLIGHT_SPOT:
3339 object->lightPosn[0] = pLight->Position.x;
3340 object->lightPosn[1] = pLight->Position.y;
3341 object->lightPosn[2] = pLight->Position.z;
3342 object->lightPosn[3] = 1.0;
3345 object->lightDirn[0] = pLight->Direction.x;
3346 object->lightDirn[1] = pLight->Direction.y;
3347 object->lightDirn[2] = pLight->Direction.z;
3348 object->lightDirn[3] = 1.0;
3351 * opengl-ish and d3d-ish spot lights use too different models for the
3352 * light "intensity" as a function of the angle towards the main light direction,
3353 * so we only can approximate very roughly.
3354 * however spot lights are rather rarely used in games (if ever used at all).
3355 * furthermore if still used, probably nobody pays attention to such details.
3357 if (pLight->Falloff == 0) {
3358 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
3359 * falloff resp. exponent parameter as an exponent, so the spot light lighting
3360 * will always be 1.0 for both of them, and we don't have to care for the
3361 * rest of the rather complex calculation
3363 object->exponent = 0;
3365 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
3366 if (rho < 0.0001) rho = 0.0001f;
3367 object->exponent = -0.3/log(cos(rho/2));
3369 if (object->exponent > 128.0) {
3370 object->exponent = 128.0;
3372 object->cutoff = pLight->Phi*90/M_PI;
3378 FIXME("Unrecognized light type %d\n", pLight->Type);
3381 /* Update the live definitions if the light is currently assigned a glIndex */
3382 if (object->glIndex != -1 && !This->isRecordingState) {
3383 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
3388 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
3389 PLIGHTINFOEL *lightInfo = NULL;
3390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3391 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
3393 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
3395 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3396 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3397 if(lightInfo->OriginalIndex == Index) break;
3401 if (lightInfo == NULL) {
3402 TRACE("Light information requested but light not defined\n");
3403 return WINED3DERR_INVALIDCALL;
3406 *pLight = lightInfo->OriginalParms;
3411 * Get / Set Light Enable
3412 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
3414 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
3415 PLIGHTINFOEL *lightInfo = NULL;
3416 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3417 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3419 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
3421 /* Tests show true = 128...not clear why */
3422 Enable = Enable? 128: 0;
3424 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3425 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3426 if(lightInfo->OriginalIndex == Index) break;
3429 TRACE("Found light: %p\n", lightInfo);
3431 /* Special case - enabling an undefined light creates one with a strict set of parms! */
3432 if (lightInfo == NULL) {
3434 TRACE("Light enabled requested but light not defined, so defining one!\n");
3435 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
3437 /* Search for it again! Should be fairly quick as near head of list */
3438 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3439 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3440 if(lightInfo->OriginalIndex == Index) break;
3443 if (lightInfo == NULL) {
3444 FIXME("Adding default lights has failed dismally\n");
3445 return WINED3DERR_INVALIDCALL;
3449 lightInfo->enabledChanged = TRUE;
3451 if(lightInfo->glIndex != -1) {
3452 if(!This->isRecordingState) {
3453 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
3456 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
3457 lightInfo->glIndex = -1;
3459 TRACE("Light already disabled, nothing to do\n");
3461 lightInfo->enabled = FALSE;
3463 lightInfo->enabled = TRUE;
3464 if (lightInfo->glIndex != -1) {
3466 TRACE("Nothing to do as light was enabled\n");
3469 /* Find a free gl light */
3470 for(i = 0; i < This->maxConcurrentLights; i++) {
3471 if(This->updateStateBlock->activeLights[i] == NULL) {
3472 This->updateStateBlock->activeLights[i] = lightInfo;
3473 lightInfo->glIndex = i;
3477 if(lightInfo->glIndex == -1) {
3478 /* Our tests show that Windows returns D3D_OK in this situation, even with
3479 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3480 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3481 * as well for those lights.
3483 * TODO: Test how this affects rendering
3485 WARN("Too many concurrently active lights\n");
3489 /* i == lightInfo->glIndex */
3490 if(!This->isRecordingState) {
3491 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3499 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3501 PLIGHTINFOEL *lightInfo = NULL;
3502 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3504 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3505 TRACE("(%p) : for idx(%d)\n", This, Index);
3507 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3508 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3509 if(lightInfo->OriginalIndex == Index) break;
3513 if (lightInfo == NULL) {
3514 TRACE("Light enabled state requested but light not defined\n");
3515 return WINED3DERR_INVALIDCALL;
3517 /* true is 128 according to SetLightEnable */
3518 *pEnable = lightInfo->enabled ? 128 : 0;
3523 * Get / Set Clip Planes
3525 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3526 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3527 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3529 /* Validate Index */
3530 if (Index >= GL_LIMITS(clipplanes)) {
3531 TRACE("Application has requested clipplane this device doesn't support\n");
3532 return WINED3DERR_INVALIDCALL;
3535 This->updateStateBlock->changed.clipplane |= 1 << Index;
3537 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3538 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3539 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3540 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3541 TRACE("Application is setting old values over, nothing to do\n");
3545 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3546 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3547 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3548 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3550 /* Handle recording of state blocks */
3551 if (This->isRecordingState) {
3552 TRACE("Recording... not performing anything\n");
3556 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3561 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3562 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3563 TRACE("(%p) : for idx %d\n", This, Index);
3565 /* Validate Index */
3566 if (Index >= GL_LIMITS(clipplanes)) {
3567 TRACE("Application has requested clipplane this device doesn't support\n");
3568 return WINED3DERR_INVALIDCALL;
3571 pPlane[0] = This->stateBlock->clipplane[Index][0];
3572 pPlane[1] = This->stateBlock->clipplane[Index][1];
3573 pPlane[2] = This->stateBlock->clipplane[Index][2];
3574 pPlane[3] = This->stateBlock->clipplane[Index][3];
3579 * Get / Set Clip Plane Status
3580 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3582 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3583 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3584 FIXME("(%p) : stub\n", This);
3585 if (NULL == pClipStatus) {
3586 return WINED3DERR_INVALIDCALL;
3588 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3589 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3593 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3594 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3595 FIXME("(%p) : stub\n", This);
3596 if (NULL == pClipStatus) {
3597 return WINED3DERR_INVALIDCALL;
3599 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3600 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3605 * Get / Set Material
3607 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3608 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3610 This->updateStateBlock->changed.material = TRUE;
3611 This->updateStateBlock->material = *pMaterial;
3613 /* Handle recording of state blocks */
3614 if (This->isRecordingState) {
3615 TRACE("Recording... not performing anything\n");
3619 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3623 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3625 *pMaterial = This->updateStateBlock->material;
3626 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3627 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3628 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3629 pMaterial->Ambient.b, pMaterial->Ambient.a);
3630 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3631 pMaterial->Specular.b, pMaterial->Specular.a);
3632 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3633 pMaterial->Emissive.b, pMaterial->Emissive.a);
3634 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3642 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DBuffer* pIndexData) {
3643 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3644 IWineD3DBuffer *oldIdxs;
3646 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3647 oldIdxs = This->updateStateBlock->pIndexData;
3649 This->updateStateBlock->changed.indices = TRUE;
3650 This->updateStateBlock->pIndexData = pIndexData;
3652 /* Handle recording of state blocks */
3653 if (This->isRecordingState) {
3654 TRACE("Recording... not performing anything\n");
3655 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
3656 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
3660 if(oldIdxs != pIndexData) {
3661 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3663 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
3664 IWineD3DBuffer_AddRef(pIndexData);
3667 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
3668 IWineD3DBuffer_Release(oldIdxs);
3675 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DBuffer** ppIndexData) {
3676 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3678 *ppIndexData = This->stateBlock->pIndexData;
3680 /* up ref count on ppindexdata */
3682 IWineD3DBuffer_AddRef(*ppIndexData);
3683 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3685 TRACE("(%p) No index data set\n", This);
3687 TRACE("Returning %p\n", *ppIndexData);
3692 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3693 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3695 TRACE("(%p)->(%d)\n", This, BaseIndex);
3697 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3698 TRACE("Application is setting the old value over, nothing to do\n");
3702 This->updateStateBlock->baseVertexIndex = BaseIndex;
3704 if (This->isRecordingState) {
3705 TRACE("Recording... not performing anything\n");
3708 /* The base vertex index affects the stream sources */
3709 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3713 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3714 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3715 TRACE("(%p) : base_index %p\n", This, base_index);
3717 *base_index = This->stateBlock->baseVertexIndex;
3719 TRACE("Returning %u\n", *base_index);
3725 * Get / Set Viewports
3727 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3728 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3730 TRACE("(%p)\n", This);
3731 This->updateStateBlock->changed.viewport = TRUE;
3732 This->updateStateBlock->viewport = *pViewport;
3734 /* Handle recording of state blocks */
3735 if (This->isRecordingState) {
3736 TRACE("Recording... not performing anything\n");
3740 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3741 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3743 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3748 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3749 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3750 TRACE("(%p)\n", This);
3751 *pViewport = This->stateBlock->viewport;
3756 * Get / Set Render States
3757 * TODO: Verify against dx9 definitions
3759 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3761 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3762 DWORD oldValue = This->stateBlock->renderState[State];
3764 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3766 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3767 This->updateStateBlock->renderState[State] = Value;
3769 /* Handle recording of state blocks */
3770 if (This->isRecordingState) {
3771 TRACE("Recording... not performing anything\n");
3775 /* Compared here and not before the assignment to allow proper stateblock recording */
3776 if(Value == oldValue) {
3777 TRACE("Application is setting the old value over, nothing to do\n");
3779 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3785 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3786 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3787 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3788 *pValue = This->stateBlock->renderState[State];
3793 * Get / Set Sampler States
3794 * TODO: Verify against dx9 definitions
3797 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3798 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3801 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3802 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3804 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3805 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3808 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3809 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3810 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3813 * SetSampler is designed to allow for more than the standard up to 8 textures
3814 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3815 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3817 * http://developer.nvidia.com/object/General_FAQ.html#t6
3819 * There are two new settings for GForce
3821 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3822 * and the texture one:
3823 * GL_MAX_TEXTURE_COORDS_ARB.
3824 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3827 oldValue = This->stateBlock->samplerState[Sampler][Type];
3828 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3829 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3831 /* Handle recording of state blocks */
3832 if (This->isRecordingState) {
3833 TRACE("Recording... not performing anything\n");
3837 if(oldValue == Value) {
3838 TRACE("Application is setting the old value over, nothing to do\n");
3842 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3847 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3848 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3850 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3851 This, Sampler, debug_d3dsamplerstate(Type), Type);
3853 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3854 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3857 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3858 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3859 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3861 *Value = This->stateBlock->samplerState[Sampler][Type];
3862 TRACE("(%p) : Returning %#x\n", This, *Value);
3867 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3868 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3870 This->updateStateBlock->changed.scissorRect = TRUE;
3871 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3872 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3875 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3877 if(This->isRecordingState) {
3878 TRACE("Recording... not performing anything\n");
3882 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3887 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3888 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3890 *pRect = This->updateStateBlock->scissorRect;
3891 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3895 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3897 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3899 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3901 This->updateStateBlock->vertexDecl = pDecl;
3902 This->updateStateBlock->changed.vertexDecl = TRUE;
3904 if (This->isRecordingState) {
3905 TRACE("Recording... not performing anything\n");
3907 } else if(pDecl == oldDecl) {
3908 /* Checked after the assignment to allow proper stateblock recording */
3909 TRACE("Application is setting the old declaration over, nothing to do\n");
3913 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3917 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3918 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3920 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3922 *ppDecl = This->stateBlock->vertexDecl;
3923 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3927 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3928 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3929 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3931 This->updateStateBlock->vertexShader = pShader;
3932 This->updateStateBlock->changed.vertexShader = TRUE;
3934 if (This->isRecordingState) {
3935 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3936 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3937 TRACE("Recording... not performing anything\n");
3939 } else if(oldShader == pShader) {
3940 /* Checked here to allow proper stateblock recording */
3941 TRACE("App is setting the old shader over, nothing to do\n");
3945 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3946 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3947 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3949 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3954 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3955 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3957 if (NULL == ppShader) {
3958 return WINED3DERR_INVALIDCALL;
3960 *ppShader = This->stateBlock->vertexShader;
3961 if( NULL != *ppShader)
3962 IWineD3DVertexShader_AddRef(*ppShader);
3964 TRACE("(%p) : returning %p\n", This, *ppShader);
3968 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3969 IWineD3DDevice *iface,
3971 CONST BOOL *srcData,
3974 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3975 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3977 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3978 iface, srcData, start, count);
3980 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3982 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3983 for (i = 0; i < cnt; i++)
3984 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3986 for (i = start; i < cnt + start; ++i) {
3987 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3990 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3995 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3996 IWineD3DDevice *iface,
4001 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4002 int cnt = min(count, MAX_CONST_B - start);
4004 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4005 iface, dstData, start, count);
4007 if (dstData == NULL || cnt < 0)
4008 return WINED3DERR_INVALIDCALL;
4010 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
4014 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
4015 IWineD3DDevice *iface,
4020 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4021 unsigned int i, cnt = min(count, MAX_CONST_I - start);
4023 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4024 iface, srcData, start, count);
4026 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
4028 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4029 for (i = 0; i < cnt; i++)
4030 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4031 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4033 for (i = start; i < cnt + start; ++i) {
4034 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
4037 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
4042 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
4043 IWineD3DDevice *iface,
4048 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4049 int cnt = min(count, MAX_CONST_I - start);
4051 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4052 iface, dstData, start, count);
4054 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
4055 return WINED3DERR_INVALIDCALL;
4057 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4061 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
4062 IWineD3DDevice *iface,
4064 CONST float *srcData,
4067 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4070 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4071 iface, srcData, start, count);
4073 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4074 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
4075 return WINED3DERR_INVALIDCALL;
4077 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4079 for (i = 0; i < count; i++)
4080 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4081 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4084 if (!This->isRecordingState)
4086 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
4087 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
4090 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
4091 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
4096 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
4097 IWineD3DDevice *iface,
4102 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4103 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
4105 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4106 iface, dstData, start, count);
4108 if (dstData == NULL || cnt < 0)
4109 return WINED3DERR_INVALIDCALL;
4111 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4115 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
4117 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
4119 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
4123 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
4124 int i = This->rev_tex_unit_map[unit];
4125 int j = This->texUnitMap[stage];
4127 This->texUnitMap[stage] = unit;
4128 if (i != -1 && i != stage) {
4129 This->texUnitMap[i] = -1;
4132 This->rev_tex_unit_map[unit] = stage;
4133 if (j != -1 && j != unit) {
4134 This->rev_tex_unit_map[j] = -1;
4138 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
4141 This->fixed_function_usage_map = 0;
4142 for (i = 0; i < MAX_TEXTURES; ++i) {
4143 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
4144 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
4145 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
4146 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
4147 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
4148 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
4149 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
4150 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
4152 if (color_op == WINED3DTOP_DISABLE) {
4153 /* Not used, and disable higher stages */
4157 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
4158 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
4159 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
4160 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
4161 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
4162 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
4163 This->fixed_function_usage_map |= (1 << i);
4166 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
4167 This->fixed_function_usage_map |= (1 << (i + 1));
4172 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
4173 unsigned int i, tex;
4176 device_update_fixed_function_usage_map(This);
4177 ffu_map = This->fixed_function_usage_map;
4179 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
4180 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
4181 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
4183 if (!(ffu_map & 1)) continue;
4185 if (This->texUnitMap[i] != i) {
4186 device_map_stage(This, i, i);
4187 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
4188 markTextureStagesDirty(This, i);
4194 /* Now work out the mapping */
4196 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
4198 if (!(ffu_map & 1)) continue;
4200 if (This->texUnitMap[i] != tex) {
4201 device_map_stage(This, i, tex);
4202 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
4203 markTextureStagesDirty(This, i);
4210 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
4211 const DWORD *sampler_tokens =
4212 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
4215 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
4216 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
4217 device_map_stage(This, i, i);
4218 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
4219 if (i < MAX_TEXTURES) {
4220 markTextureStagesDirty(This, i);
4226 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
4227 const DWORD *vshader_sampler_tokens, int unit)
4229 int current_mapping = This->rev_tex_unit_map[unit];
4231 if (current_mapping == -1) {
4232 /* Not currently used */
4236 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
4237 /* Used by a fragment sampler */
4239 if (!pshader_sampler_tokens) {
4240 /* No pixel shader, check fixed function */
4241 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
4244 /* Pixel shader, check the shader's sampler map */
4245 return !pshader_sampler_tokens[current_mapping];
4248 /* Used by a vertex sampler */
4249 return !vshader_sampler_tokens[current_mapping];
4252 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
4253 const DWORD *vshader_sampler_tokens =
4254 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
4255 const DWORD *pshader_sampler_tokens = NULL;
4256 int start = GL_LIMITS(combined_samplers) - 1;
4260 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
4262 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
4263 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
4264 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
4267 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
4268 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
4269 if (vshader_sampler_tokens[i]) {
4270 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
4272 /* Already mapped somewhere */
4276 while (start >= 0) {
4277 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
4278 device_map_stage(This, vsampler_idx, start);
4279 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
4291 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
4292 BOOL vs = use_vs(This->stateBlock);
4293 BOOL ps = use_ps(This->stateBlock);
4296 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
4297 * that would be really messy and require shader recompilation
4298 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
4299 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
4302 device_map_psamplers(This);
4304 device_map_fixed_function_samplers(This);
4308 device_map_vsamplers(This, ps);
4312 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
4313 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4314 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
4315 This->updateStateBlock->pixelShader = pShader;
4316 This->updateStateBlock->changed.pixelShader = TRUE;
4318 /* Handle recording of state blocks */
4319 if (This->isRecordingState) {
4320 TRACE("Recording... not performing anything\n");
4323 if (This->isRecordingState) {
4324 TRACE("Recording... not performing anything\n");
4325 if(pShader) IWineD3DPixelShader_AddRef(pShader);
4326 if(oldShader) IWineD3DPixelShader_Release(oldShader);
4330 if(pShader == oldShader) {
4331 TRACE("App is setting the old pixel shader over, nothing to do\n");
4335 if(pShader) IWineD3DPixelShader_AddRef(pShader);
4336 if(oldShader) IWineD3DPixelShader_Release(oldShader);
4338 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
4339 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4344 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
4345 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4347 if (NULL == ppShader) {
4348 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
4349 return WINED3DERR_INVALIDCALL;
4352 *ppShader = This->stateBlock->pixelShader;
4353 if (NULL != *ppShader) {
4354 IWineD3DPixelShader_AddRef(*ppShader);
4356 TRACE("(%p) : returning %p\n", This, *ppShader);
4360 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
4361 IWineD3DDevice *iface,
4363 CONST BOOL *srcData,
4366 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4367 unsigned int i, cnt = min(count, MAX_CONST_B - start);
4369 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
4370 iface, srcData, start, count);
4372 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
4374 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
4375 for (i = 0; i < cnt; i++)
4376 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
4378 for (i = start; i < cnt + start; ++i) {
4379 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
4382 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4387 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
4388 IWineD3DDevice *iface,
4393 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4394 int cnt = min(count, MAX_CONST_B - start);
4396 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4397 iface, dstData, start, count);
4399 if (dstData == NULL || cnt < 0)
4400 return WINED3DERR_INVALIDCALL;
4402 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4406 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4407 IWineD3DDevice *iface,
4412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4413 unsigned int i, cnt = min(count, MAX_CONST_I - start);
4415 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
4416 iface, srcData, start, count);
4418 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
4420 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4421 for (i = 0; i < cnt; i++)
4422 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4423 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4425 for (i = start; i < cnt + start; ++i) {
4426 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
4429 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4434 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4435 IWineD3DDevice *iface,
4440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4441 int cnt = min(count, MAX_CONST_I - start);
4443 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4444 iface, dstData, start, count);
4446 if (dstData == NULL || cnt < 0)
4447 return WINED3DERR_INVALIDCALL;
4449 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4453 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4454 IWineD3DDevice *iface,
4456 CONST float *srcData,
4459 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4462 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4463 iface, srcData, start, count);
4465 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4466 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4467 return WINED3DERR_INVALIDCALL;
4469 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4471 for (i = 0; i < count; i++)
4472 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4473 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4476 if (!This->isRecordingState)
4478 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
4479 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4482 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
4483 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
4488 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4489 IWineD3DDevice *iface,
4494 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4495 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4497 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4498 iface, dstData, start, count);
4500 if (dstData == NULL || cnt < 0)
4501 return WINED3DERR_INVALIDCALL;
4503 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4507 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4508 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4509 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags)
4511 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4513 DWORD DestFVF = dest->fvf;
4515 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4519 if (stream_info->elements[WINED3D_FFP_NORMAL].data)
4521 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4524 if (!stream_info->elements[WINED3D_FFP_POSITION].data)
4526 ERR("Source has no position mask\n");
4527 return WINED3DERR_INVALIDCALL;
4530 /* We might access VBOs from this code, so hold the lock */
4533 if (dest->resource.allocatedMemory == NULL) {
4534 /* This may happen if we do direct locking into a vbo. Unlikely,
4535 * but theoretically possible(ddraw processvertices test)
4537 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4538 if(!dest->resource.allocatedMemory) {
4540 ERR("Out of memory\n");
4541 return E_OUTOFMEMORY;
4543 if (dest->buffer_object)
4546 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4547 checkGLcall("glBindBufferARB");
4548 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4550 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4552 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4553 checkGLcall("glUnmapBufferARB");
4557 /* Get a pointer into the destination vbo(create one if none exists) and
4558 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4560 if (!dest->buffer_object && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT))
4562 dest->flags |= WINED3D_BUFFER_CREATEBO;
4563 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
4566 if (dest->buffer_object)
4568 unsigned char extrabytes = 0;
4569 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4570 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4571 * this may write 4 extra bytes beyond the area that should be written
4573 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4574 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4575 if(!dest_conv_addr) {
4576 ERR("Out of memory\n");
4577 /* Continue without storing converted vertices */
4579 dest_conv = dest_conv_addr;
4583 * a) WINED3DRS_CLIPPING is enabled
4584 * b) WINED3DVOP_CLIP is passed
4586 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4587 static BOOL warned = FALSE;
4589 * The clipping code is not quite correct. Some things need
4590 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4591 * so disable clipping for now.
4592 * (The graphics in Half-Life are broken, and my processvertices
4593 * test crashes with IDirect3DDevice3)
4599 FIXME("Clipping is broken and disabled for now\n");
4601 } else doClip = FALSE;
4602 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4604 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4607 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4608 WINED3DTS_PROJECTION,
4610 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4611 WINED3DTS_WORLDMATRIX(0),
4614 TRACE("View mat:\n");
4615 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);
4616 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);
4617 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);
4618 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);
4620 TRACE("Proj mat:\n");
4621 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);
4622 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);
4623 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);
4624 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);
4626 TRACE("World mat:\n");
4627 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);
4628 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);
4629 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);
4630 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);
4632 /* Get the viewport */
4633 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4634 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4635 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4637 multiply_matrix(&mat,&view_mat,&world_mat);
4638 multiply_matrix(&mat,&proj_mat,&mat);
4640 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4642 for (i = 0; i < dwCount; i+= 1) {
4643 unsigned int tex_index;
4645 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4646 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4647 /* The position first */
4648 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
4649 const float *p = (const float *)(element->data + i * element->stride);
4651 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4653 /* Multiplication with world, view and projection matrix */
4654 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);
4655 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);
4656 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);
4657 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);
4659 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4661 /* WARNING: The following things are taken from d3d7 and were not yet checked
4662 * against d3d8 or d3d9!
4665 /* Clipping conditions: From msdn
4667 * A vertex is clipped if it does not match the following requirements
4671 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4673 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4674 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4679 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4680 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4683 /* "Normal" viewport transformation (not clipped)
4684 * 1) The values are divided by rhw
4685 * 2) The y axis is negative, so multiply it with -1
4686 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4687 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4688 * 4) Multiply x with Width/2 and add Width/2
4689 * 5) The same for the height
4690 * 6) Add the viewpoint X and Y to the 2D coordinates and
4691 * The minimum Z value to z
4692 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4694 * Well, basically it's simply a linear transformation into viewport
4706 z *= vp.MaxZ - vp.MinZ;
4708 x += vp.Width / 2 + vp.X;
4709 y += vp.Height / 2 + vp.Y;
4714 /* That vertex got clipped
4715 * Contrary to OpenGL it is not dropped completely, it just
4716 * undergoes a different calculation.
4718 TRACE("Vertex got clipped\n");
4725 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4726 * outside of the main vertex buffer memory. That needs some more
4731 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4734 ( (float *) dest_ptr)[0] = x;
4735 ( (float *) dest_ptr)[1] = y;
4736 ( (float *) dest_ptr)[2] = z;
4737 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4739 dest_ptr += 3 * sizeof(float);
4741 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4742 dest_ptr += sizeof(float);
4747 ( (float *) dest_conv)[0] = x * w;
4748 ( (float *) dest_conv)[1] = y * w;
4749 ( (float *) dest_conv)[2] = z * w;
4750 ( (float *) dest_conv)[3] = w;
4752 dest_conv += 3 * sizeof(float);
4754 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4755 dest_conv += sizeof(float);
4759 if (DestFVF & WINED3DFVF_PSIZE) {
4760 dest_ptr += sizeof(DWORD);
4761 if(dest_conv) dest_conv += sizeof(DWORD);
4763 if (DestFVF & WINED3DFVF_NORMAL) {
4764 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4765 const float *normal = (const float *)(element->data + i * element->stride);
4766 /* AFAIK this should go into the lighting information */
4767 FIXME("Didn't expect the destination to have a normal\n");
4768 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4770 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4774 if (DestFVF & WINED3DFVF_DIFFUSE) {
4775 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4776 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4778 static BOOL warned = FALSE;
4781 ERR("No diffuse color in source, but destination has one\n");
4785 *( (DWORD *) dest_ptr) = 0xffffffff;
4786 dest_ptr += sizeof(DWORD);
4789 *( (DWORD *) dest_conv) = 0xffffffff;
4790 dest_conv += sizeof(DWORD);
4794 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4796 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4797 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4798 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4799 dest_conv += sizeof(DWORD);
4804 if (DestFVF & WINED3DFVF_SPECULAR) {
4805 /* What's the color value in the feedback buffer? */
4806 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4807 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4809 static BOOL warned = FALSE;
4812 ERR("No specular color in source, but destination has one\n");
4816 *( (DWORD *) dest_ptr) = 0xFF000000;
4817 dest_ptr += sizeof(DWORD);
4820 *( (DWORD *) dest_conv) = 0xFF000000;
4821 dest_conv += sizeof(DWORD);
4825 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4827 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4828 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4829 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4830 dest_conv += sizeof(DWORD);
4835 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4836 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4837 const float *tex_coord = (const float *)(element->data + i * element->stride);
4839 ERR("No source texture, but destination requests one\n");
4840 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4841 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4844 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4846 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4853 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4854 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4855 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4856 dwCount * get_flexible_vertex_size(DestFVF),
4858 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4859 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4866 #undef copy_and_next
4868 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4869 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags)
4871 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4872 struct wined3d_stream_info stream_info;
4873 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4874 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4877 ERR("Output vertex declaration not implemented yet\n");
4880 /* Need any context to write to the vbo. */
4881 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4883 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4884 * control the streamIsUP flag, thus restore it afterwards.
4886 This->stateBlock->streamIsUP = FALSE;
4887 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4888 This->stateBlock->streamIsUP = streamWasUP;
4890 if(vbo || SrcStartIndex) {
4892 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4893 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4895 * Also get the start index in, but only loop over all elements if there's something to add at all.
4897 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4899 struct wined3d_stream_info_element *e = &stream_info.elements[i];
4900 if (e->buffer_object)
4902 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
4903 e->buffer_object = 0;
4904 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)vb->resource.allocatedMemory);
4906 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4907 vb->buffer_object = 0;
4910 if (e->data) e->data += e->stride * SrcStartIndex;
4914 return process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4915 (struct wined3d_buffer *)pDestBuffer, Flags);
4919 * Get / Set Texture Stage States
4920 * TODO: Verify against dx9 definitions
4922 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4924 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4926 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4928 if (Stage >= MAX_TEXTURES) {
4929 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4933 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4934 This->updateStateBlock->textureState[Stage][Type] = Value;
4936 if (This->isRecordingState) {
4937 TRACE("Recording... not performing anything\n");
4941 /* Checked after the assignments to allow proper stateblock recording */
4942 if(oldValue == Value) {
4943 TRACE("App is setting the old value over, nothing to do\n");
4947 if(Stage > This->stateBlock->lowest_disabled_stage &&
4948 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4949 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4950 * Changes in other states are important on disabled stages too
4955 if(Type == WINED3DTSS_COLOROP) {
4958 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4959 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4960 * they have to be disabled
4962 * The current stage is dirtified below.
4964 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4965 TRACE("Additionally dirtifying stage %u\n", i);
4966 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4968 This->stateBlock->lowest_disabled_stage = Stage;
4969 TRACE("New lowest disabled: %u\n", Stage);
4970 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4971 /* Previously disabled stage enabled. Stages above it may need enabling
4972 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4973 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4975 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4978 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4979 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4982 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4983 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4985 This->stateBlock->lowest_disabled_stage = i;
4986 TRACE("New lowest disabled: %u\n", i);
4990 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4995 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4997 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4998 *pValue = This->updateStateBlock->textureState[Stage][Type];
5005 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
5006 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5007 IWineD3DBaseTexture *oldTexture;
5009 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
5011 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
5012 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
5015 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
5016 ERR("Current stage overflows textures array (stage %d)\n", Stage);
5017 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
5020 oldTexture = This->updateStateBlock->textures[Stage];
5022 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
5023 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
5025 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
5026 return WINED3DERR_INVALIDCALL;
5029 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
5030 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
5032 This->updateStateBlock->changed.textures |= 1 << Stage;
5033 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
5034 This->updateStateBlock->textures[Stage] = pTexture;
5036 /* Handle recording of state blocks */
5037 if (This->isRecordingState) {
5038 TRACE("Recording... not performing anything\n");
5042 if(oldTexture == pTexture) {
5043 TRACE("App is setting the same texture again, nothing to do\n");
5047 /** NOTE: MSDN says that setTexture increases the reference count,
5048 * and that the application must set the texture back to null (or have a leaky application),
5049 * This means we should pass the refcount up to the parent
5050 *******************************/
5051 if (NULL != This->updateStateBlock->textures[Stage]) {
5052 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
5053 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
5054 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
5056 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
5058 if (!oldTexture || dimensions != IWineD3DBaseTexture_GetTextureDimensions(oldTexture))
5060 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
5063 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
5064 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
5065 * so the COLOROP and ALPHAOP have to be dirtified.
5067 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
5068 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
5070 if(bindCount == 1) {
5071 new->baseTexture.sampler = Stage;
5073 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
5077 if (NULL != oldTexture) {
5078 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
5079 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
5081 IWineD3DBaseTexture_Release(oldTexture);
5082 if(pTexture == NULL && Stage < MAX_TEXTURES) {
5083 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
5084 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
5087 if(bindCount && old->baseTexture.sampler == Stage) {
5089 /* Have to do a search for the other sampler(s) where the texture is bound to
5090 * Shouldn't happen as long as apps bind a texture only to one stage
5092 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
5093 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5094 if(This->updateStateBlock->textures[i] == oldTexture) {
5095 old->baseTexture.sampler = i;
5102 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
5107 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
5108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5110 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
5112 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
5113 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
5116 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
5117 ERR("Current stage overflows textures array (stage %d)\n", Stage);
5118 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
5121 *ppTexture=This->stateBlock->textures[Stage];
5123 IWineD3DBaseTexture_AddRef(*ppTexture);
5125 TRACE("(%p) : Returning %p\n", This, *ppTexture);
5133 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
5134 IWineD3DSurface **ppBackBuffer) {
5135 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5136 IWineD3DSwapChain *swapChain;
5139 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
5141 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5142 if (hr == WINED3D_OK) {
5143 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
5144 IWineD3DSwapChain_Release(swapChain);
5146 *ppBackBuffer = NULL;
5151 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
5152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5153 WARN("(%p) : stub, calling idirect3d for now\n", This);
5154 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
5157 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
5158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5159 IWineD3DSwapChain *swapChain;
5162 if(iSwapChain > 0) {
5163 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5164 if (hr == WINED3D_OK) {
5165 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
5166 IWineD3DSwapChain_Release(swapChain);
5168 FIXME("(%p) Error getting display mode\n", This);
5171 /* Don't read the real display mode,
5172 but return the stored mode instead. X11 can't change the color
5173 depth, and some apps are pretty angry if they SetDisplayMode from
5174 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
5176 Also don't relay to the swapchain because with ddraw it's possible
5177 that there isn't a swapchain at all */
5178 pMode->Width = This->ddraw_width;
5179 pMode->Height = This->ddraw_height;
5180 pMode->Format = This->ddraw_format;
5181 pMode->RefreshRate = 0;
5189 * Stateblock related functions
5192 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
5193 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5194 IWineD3DStateBlock *stateblock;
5197 TRACE("(%p)\n", This);
5199 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
5201 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
5202 if (FAILED(hr)) return hr;
5204 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
5205 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
5206 This->isRecordingState = TRUE;
5208 TRACE("(%p) recording stateblock %p\n", This, stateblock);
5213 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
5214 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5216 IWineD3DStateBlockImpl *object = This->updateStateBlock;
5218 if (!This->isRecordingState) {
5219 WARN("(%p) not recording! returning error\n", This);
5220 *ppStateBlock = NULL;
5221 return WINED3DERR_INVALIDCALL;
5224 for (i = 0; i <= WINEHIGHEST_RENDER_STATE >> 5; ++i)
5226 DWORD map = object->changed.renderState[i];
5227 for (j = 0; map; map >>= 1, ++j)
5229 if (!(map & 1)) continue;
5231 object->contained_render_states[object->num_contained_render_states++] = (i << 5) | j;
5235 for (i = 0; i <= HIGHEST_TRANSFORMSTATE >> 5; ++i)
5237 DWORD map = object->changed.transform[i];
5238 for (j = 0; map; map >>= 1, ++j)
5240 if (!(map & 1)) continue;
5242 object->contained_transform_states[object->num_contained_transform_states++] = (i << 5) | j;
5245 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
5246 if(object->changed.vertexShaderConstantsF[i]) {
5247 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
5248 object->num_contained_vs_consts_f++;
5251 for(i = 0; i < MAX_CONST_I; i++) {
5252 if (object->changed.vertexShaderConstantsI & (1 << i))
5254 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
5255 object->num_contained_vs_consts_i++;
5258 for(i = 0; i < MAX_CONST_B; i++) {
5259 if (object->changed.vertexShaderConstantsB & (1 << i))
5261 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
5262 object->num_contained_vs_consts_b++;
5265 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
5267 if (object->changed.pixelShaderConstantsF[i])
5269 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
5270 ++object->num_contained_ps_consts_f;
5273 for(i = 0; i < MAX_CONST_I; i++) {
5274 if (object->changed.pixelShaderConstantsI & (1 << i))
5276 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
5277 object->num_contained_ps_consts_i++;
5280 for(i = 0; i < MAX_CONST_B; i++) {
5281 if (object->changed.pixelShaderConstantsB & (1 << i))
5283 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
5284 object->num_contained_ps_consts_b++;
5287 for(i = 0; i < MAX_TEXTURES; i++) {
5288 DWORD map = object->changed.textureState[i];
5290 for(j = 0; map; map >>= 1, ++j)
5292 if (!(map & 1)) continue;
5294 object->contained_tss_states[object->num_contained_tss_states].stage = i;
5295 object->contained_tss_states[object->num_contained_tss_states].state = j;
5296 ++object->num_contained_tss_states;
5299 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
5300 DWORD map = object->changed.samplerState[i];
5302 for (j = 0; map; map >>= 1, ++j)
5304 if (!(map & 1)) continue;
5306 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
5307 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
5308 ++object->num_contained_sampler_states;
5312 *ppStateBlock = (IWineD3DStateBlock*) object;
5313 This->isRecordingState = FALSE;
5314 This->updateStateBlock = This->stateBlock;
5315 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
5316 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5317 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
5322 * Scene related functions
5324 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
5325 /* At the moment we have no need for any functionality at the beginning
5327 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5328 TRACE("(%p)\n", This);
5331 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
5332 return WINED3DERR_INVALIDCALL;
5334 This->inScene = TRUE;
5338 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
5339 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5340 TRACE("(%p)\n", This);
5342 if(!This->inScene) {
5343 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
5344 return WINED3DERR_INVALIDCALL;
5347 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5348 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5350 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
5354 This->inScene = FALSE;
5358 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
5359 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5360 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5361 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5362 IWineD3DSwapChain *swapChain = NULL;
5364 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5366 TRACE("(%p) Presenting the frame\n", This);
5368 for(i = 0 ; i < swapchains ; i ++) {
5370 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
5371 TRACE("presentinng chain %d, %p\n", i, swapChain);
5372 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5373 IWineD3DSwapChain_Release(swapChain);
5379 /* Not called from the VTable (internal subroutine) */
5380 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
5381 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
5382 float Z, DWORD Stencil) {
5383 GLbitfield glMask = 0;
5385 WINED3DRECT curRect;
5387 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
5388 UINT drawable_width, drawable_height;
5389 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
5390 IWineD3DSwapChainImpl *swapchain = NULL;
5392 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5393 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5394 * for the cleared parts, and the untouched parts.
5396 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5397 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5398 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5399 * checking all this if the dest surface is in the drawable anyway.
5401 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5403 if(vp->X != 0 || vp->Y != 0 ||
5404 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5405 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5408 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5409 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5410 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5411 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5412 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5415 if(Count > 0 && pRects && (
5416 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5417 pRects[0].x2 < target->currentDesc.Width ||
5418 pRects[0].y2 < target->currentDesc.Height)) {
5419 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5426 target->get_drawable_size(target, &drawable_width, &drawable_height);
5428 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5431 /* Only set the values up once, as they are not changing */
5432 if (Flags & WINED3DCLEAR_STENCIL) {
5433 glClearStencil(Stencil);
5434 checkGLcall("glClearStencil");
5435 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5436 glStencilMask(0xFFFFFFFF);
5439 if (Flags & WINED3DCLEAR_ZBUFFER) {
5440 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5441 glDepthMask(GL_TRUE);
5443 checkGLcall("glClearDepth");
5444 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5445 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5447 if (vp->X != 0 || vp->Y != 0 ||
5448 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5449 surface_load_ds_location(This->stencilBufferTarget, location);
5451 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5452 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5453 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5454 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5455 surface_load_ds_location(This->stencilBufferTarget, location);
5457 else if (Count > 0 && pRects && (
5458 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5459 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5460 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5461 surface_load_ds_location(This->stencilBufferTarget, location);
5465 if (Flags & WINED3DCLEAR_TARGET) {
5466 TRACE("Clearing screen with glClear to color %x\n", Color);
5467 glClearColor(D3DCOLOR_R(Color),
5471 checkGLcall("glClearColor");
5473 /* Clear ALL colors! */
5474 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5475 glMask = glMask | GL_COLOR_BUFFER_BIT;
5478 vp_rect.left = vp->X;
5479 vp_rect.top = vp->Y;
5480 vp_rect.right = vp->X + vp->Width;
5481 vp_rect.bottom = vp->Y + vp->Height;
5482 if (!(Count > 0 && pRects)) {
5483 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5484 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5486 if(This->render_offscreen) {
5487 glScissor(vp_rect.left, vp_rect.top,
5488 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5490 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5491 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5493 checkGLcall("glScissor");
5495 checkGLcall("glClear");
5497 /* Now process each rect in turn */
5498 for (i = 0; i < Count; i++) {
5499 /* Note gl uses lower left, width/height */
5500 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5501 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5502 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5504 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5505 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5506 curRect.x1, (target->currentDesc.Height - curRect.y2),
5507 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5509 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5510 * The rectangle is not cleared, no error is returned, but further rectanlges are
5511 * still cleared if they are valid
5513 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5514 TRACE("Rectangle with negative dimensions, ignoring\n");
5518 if(This->render_offscreen) {
5519 glScissor(curRect.x1, curRect.y1,
5520 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5522 glScissor(curRect.x1, drawable_height - curRect.y2,
5523 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5525 checkGLcall("glScissor");
5528 checkGLcall("glClear");
5532 /* Restore the old values (why..?) */
5533 if (Flags & WINED3DCLEAR_STENCIL) {
5534 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5536 if (Flags & WINED3DCLEAR_TARGET) {
5537 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5538 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5539 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5540 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5541 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5543 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5544 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5546 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5548 if (Flags & WINED3DCLEAR_ZBUFFER) {
5549 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5550 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5551 surface_modify_ds_location(This->stencilBufferTarget, location);
5556 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5557 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5560 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5566 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5567 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5568 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5569 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5571 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5572 Count, pRects, Flags, Color, Z, Stencil);
5574 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5575 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5576 /* TODO: What about depth stencil buffers without stencil bits? */
5577 return WINED3DERR_INVALIDCALL;
5580 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5587 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
5588 WINED3DPRIMITIVETYPE primitive_type)
5590 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5592 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
5594 This->updateStateBlock->changed.primitive_type = TRUE;
5595 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
5598 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
5599 WINED3DPRIMITIVETYPE *primitive_type)
5601 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5603 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
5605 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
5607 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
5610 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
5612 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5614 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
5616 if(!This->stateBlock->vertexDecl) {
5617 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5618 return WINED3DERR_INVALIDCALL;
5621 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5622 if(This->stateBlock->streamIsUP) {
5623 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5624 This->stateBlock->streamIsUP = FALSE;
5627 if(This->stateBlock->loadBaseVertexIndex != 0) {
5628 This->stateBlock->loadBaseVertexIndex = 0;
5629 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5631 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5632 drawPrimitive(iface, vertex_count, 0/* NumVertices */, StartVertex /* start_idx */,
5633 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5637 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5638 UINT minIndex, UINT NumVertices, UINT startIndex, UINT index_count)
5640 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5642 IWineD3DBuffer *pIB;
5643 WINED3DBUFFER_DESC IdxBufDsc;
5646 pIB = This->stateBlock->pIndexData;
5648 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5649 * without an index buffer set. (The first time at least...)
5650 * D3D8 simply dies, but I doubt it can do much harm to return
5651 * D3DERR_INVALIDCALL there as well. */
5652 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5653 return WINED3DERR_INVALIDCALL;
5656 if(!This->stateBlock->vertexDecl) {
5657 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5658 return WINED3DERR_INVALIDCALL;
5661 if(This->stateBlock->streamIsUP) {
5662 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5663 This->stateBlock->streamIsUP = FALSE;
5665 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
5667 TRACE("(%p) : min %u, vertex count %u, startIdx %u, index count %u\n",
5668 This, minIndex, NumVertices, startIndex, index_count);
5670 IWineD3DBuffer_GetDesc(pIB, &IdxBufDsc);
5671 if (IdxBufDsc.Format == WINED3DFMT_R16_UINT) {
5677 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5678 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5679 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5682 drawPrimitive(iface, index_count, NumVertices, startIndex, idxStride,
5683 vbo ? NULL : ((struct wined3d_buffer *) pIB)->resource.allocatedMemory, minIndex);
5688 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
5689 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5691 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5694 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
5695 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
5697 if(!This->stateBlock->vertexDecl) {
5698 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5699 return WINED3DERR_INVALIDCALL;
5702 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5703 vb = This->stateBlock->streamSource[0];
5704 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5705 if (vb) IWineD3DBuffer_Release(vb);
5706 This->stateBlock->streamOffset[0] = 0;
5707 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5708 This->stateBlock->streamIsUP = TRUE;
5709 This->stateBlock->loadBaseVertexIndex = 0;
5711 /* TODO: Only mark dirty if drawing from a different UP address */
5712 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5714 drawPrimitive(iface, vertex_count, 0 /* NumVertices */, 0 /* start_idx */,
5715 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5717 /* MSDN specifies stream zero settings must be set to NULL */
5718 This->stateBlock->streamStride[0] = 0;
5719 This->stateBlock->streamSource[0] = NULL;
5721 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5722 * the new stream sources or use UP drawing again
5727 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, UINT MinVertexIndex,
5728 UINT NumVertices, UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
5729 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5732 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5736 TRACE("(%p) : MinVtxIdx %u, NumVIdx %u, index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u\n",
5737 This, MinVertexIndex, NumVertices, index_count, pIndexData,
5738 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5740 if(!This->stateBlock->vertexDecl) {
5741 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5742 return WINED3DERR_INVALIDCALL;
5745 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
5751 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5752 vb = This->stateBlock->streamSource[0];
5753 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5754 if (vb) IWineD3DBuffer_Release(vb);
5755 This->stateBlock->streamIsUP = TRUE;
5756 This->stateBlock->streamOffset[0] = 0;
5757 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5759 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5760 This->stateBlock->baseVertexIndex = 0;
5761 This->stateBlock->loadBaseVertexIndex = 0;
5762 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5763 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5764 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5766 drawPrimitive(iface, index_count, NumVertices, 0 /* start_idx */,
5767 idxStride, pIndexData, MinVertexIndex);
5769 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5770 This->stateBlock->streamSource[0] = NULL;
5771 This->stateBlock->streamStride[0] = 0;
5772 ib = This->stateBlock->pIndexData;
5774 IWineD3DBuffer_Release(ib);
5775 This->stateBlock->pIndexData = NULL;
5777 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5778 * SetStreamSource to specify a vertex buffer
5784 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5785 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
5787 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5789 /* Mark the state dirty until we have nicer tracking
5790 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5793 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5794 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5795 This->stateBlock->baseVertexIndex = 0;
5796 This->up_strided = DrawPrimStrideData;
5797 drawPrimitive(iface, vertex_count, 0, 0, 0, NULL, 0);
5798 This->up_strided = NULL;
5802 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5803 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
5804 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
5806 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5807 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5809 /* Mark the state dirty until we have nicer tracking
5810 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5813 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5814 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5815 This->stateBlock->streamIsUP = TRUE;
5816 This->stateBlock->baseVertexIndex = 0;
5817 This->up_strided = DrawPrimStrideData;
5818 drawPrimitive(iface, vertex_count, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData, 0 /* minindex */);
5819 This->up_strided = NULL;
5823 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5824 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5825 * not callable by the app directly no parameter validation checks are needed here.
5827 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5828 WINED3DLOCKED_BOX src;
5829 WINED3DLOCKED_BOX dst;
5831 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5833 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5834 * dirtification to improve loading performance.
5836 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5837 if(FAILED(hr)) return hr;
5838 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5840 IWineD3DVolume_UnlockBox(pSourceVolume);
5844 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5846 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5848 IWineD3DVolume_UnlockBox(pSourceVolume);
5850 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5855 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5856 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5857 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5858 HRESULT hr = WINED3D_OK;
5859 WINED3DRESOURCETYPE sourceType;
5860 WINED3DRESOURCETYPE destinationType;
5863 /* TODO: think about moving the code into IWineD3DBaseTexture */
5865 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5867 /* verify that the source and destination textures aren't NULL */
5868 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5869 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5870 This, pSourceTexture, pDestinationTexture);
5871 hr = WINED3DERR_INVALIDCALL;
5874 if (pSourceTexture == pDestinationTexture) {
5875 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5876 This, pSourceTexture, pDestinationTexture);
5877 hr = WINED3DERR_INVALIDCALL;
5879 /* Verify that the source and destination textures are the same type */
5880 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5881 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5883 if (sourceType != destinationType) {
5884 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5886 hr = WINED3DERR_INVALIDCALL;
5889 /* check that both textures have the identical numbers of levels */
5890 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5891 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5892 hr = WINED3DERR_INVALIDCALL;
5895 if (WINED3D_OK == hr) {
5896 IWineD3DBaseTextureImpl *pDestImpl = (IWineD3DBaseTextureImpl *) pDestinationTexture;
5898 /* Make sure that the destination texture is loaded */
5899 pDestImpl->baseTexture.internal_preload(pDestinationTexture, SRGB_RGB);
5901 /* Update every surface level of the texture */
5902 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5904 switch (sourceType) {
5905 case WINED3DRTYPE_TEXTURE:
5907 IWineD3DSurface *srcSurface;
5908 IWineD3DSurface *destSurface;
5910 for (i = 0 ; i < levels ; ++i) {
5911 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5912 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5913 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5914 IWineD3DSurface_Release(srcSurface);
5915 IWineD3DSurface_Release(destSurface);
5916 if (WINED3D_OK != hr) {
5917 WARN("(%p) : Call to update surface failed\n", This);
5923 case WINED3DRTYPE_CUBETEXTURE:
5925 IWineD3DSurface *srcSurface;
5926 IWineD3DSurface *destSurface;
5927 WINED3DCUBEMAP_FACES faceType;
5929 for (i = 0 ; i < levels ; ++i) {
5930 /* Update each cube face */
5931 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5932 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5933 if (WINED3D_OK != hr) {
5934 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5936 TRACE("Got srcSurface %p\n", srcSurface);
5938 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5939 if (WINED3D_OK != hr) {
5940 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5942 TRACE("Got desrSurface %p\n", destSurface);
5944 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5945 IWineD3DSurface_Release(srcSurface);
5946 IWineD3DSurface_Release(destSurface);
5947 if (WINED3D_OK != hr) {
5948 WARN("(%p) : Call to update surface failed\n", This);
5956 case WINED3DRTYPE_VOLUMETEXTURE:
5958 IWineD3DVolume *srcVolume = NULL;
5959 IWineD3DVolume *destVolume = NULL;
5961 for (i = 0 ; i < levels ; ++i) {
5962 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5963 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5964 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5965 IWineD3DVolume_Release(srcVolume);
5966 IWineD3DVolume_Release(destVolume);
5967 if (WINED3D_OK != hr) {
5968 WARN("(%p) : Call to update volume failed\n", This);
5976 FIXME("(%p) : Unsupported source and destination type\n", This);
5977 hr = WINED3DERR_INVALIDCALL;
5984 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5985 IWineD3DSwapChain *swapChain;
5987 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5988 if(hr == WINED3D_OK) {
5989 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5990 IWineD3DSwapChain_Release(swapChain);
5995 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5997 IWineD3DBaseTextureImpl *texture;
6000 TRACE("(%p) : %p\n", This, pNumPasses);
6002 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
6003 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
6004 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
6005 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
6007 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
6008 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
6009 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
6012 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
6013 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
6015 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
6016 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
6019 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
6020 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
6023 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
6024 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
6025 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
6030 /* return a sensible default */
6033 TRACE("returning D3D_OK\n");
6037 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
6041 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
6042 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
6043 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8
6044 || texture->resource.format_desc->format == WINED3DFMT_A8P8))
6046 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
6051 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
6052 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6055 PALETTEENTRY **palettes;
6057 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6059 if (PaletteNumber >= MAX_PALETTES) {
6060 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
6061 return WINED3DERR_INVALIDCALL;
6064 if (PaletteNumber >= This->NumberOfPalettes) {
6065 NewSize = This->NumberOfPalettes;
6068 } while(PaletteNumber >= NewSize);
6069 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
6071 ERR("Out of memory!\n");
6072 return E_OUTOFMEMORY;
6074 This->palettes = palettes;
6075 This->NumberOfPalettes = NewSize;
6078 if (!This->palettes[PaletteNumber]) {
6079 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
6080 if (!This->palettes[PaletteNumber]) {
6081 ERR("Out of memory!\n");
6082 return E_OUTOFMEMORY;
6086 for (j = 0; j < 256; ++j) {
6087 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
6088 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
6089 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
6090 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
6092 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
6093 TRACE("(%p) : returning\n", This);
6097 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
6098 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6100 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6101 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
6102 /* What happens in such situation isn't documented; Native seems to silently abort
6103 on such conditions. Return Invalid Call. */
6104 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
6105 return WINED3DERR_INVALIDCALL;
6107 for (j = 0; j < 256; ++j) {
6108 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
6109 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
6110 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
6111 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
6113 TRACE("(%p) : returning\n", This);
6117 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
6118 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6119 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
6120 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
6121 (tested with reference rasterizer). Return Invalid Call. */
6122 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
6123 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
6124 return WINED3DERR_INVALIDCALL;
6126 /*TODO: stateblocks */
6127 if (This->currentPalette != PaletteNumber) {
6128 This->currentPalette = PaletteNumber;
6129 dirtify_p8_texture_samplers(This);
6131 TRACE("(%p) : returning\n", This);
6135 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
6136 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6137 if (PaletteNumber == NULL) {
6138 WARN("(%p) : returning Invalid Call\n", This);
6139 return WINED3DERR_INVALIDCALL;
6141 /*TODO: stateblocks */
6142 *PaletteNumber = This->currentPalette;
6143 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
6147 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
6148 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6152 FIXME("(%p) : stub\n", This);
6156 This->softwareVertexProcessing = bSoftware;
6161 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
6162 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6166 FIXME("(%p) : stub\n", This);
6169 return This->softwareVertexProcessing;
6173 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
6174 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6175 IWineD3DSwapChain *swapChain;
6178 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
6180 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
6181 if(hr == WINED3D_OK){
6182 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
6183 IWineD3DSwapChain_Release(swapChain);
6185 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
6191 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
6192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6194 if(nSegments != 0.0f) {
6197 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
6204 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
6205 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6209 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
6215 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
6216 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6217 /** TODO: remove casts to IWineD3DSurfaceImpl
6218 * NOTE: move code to surface to accomplish this
6219 ****************************************/
6220 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
6221 int srcWidth, srcHeight;
6222 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
6223 WINED3DFORMAT destFormat, srcFormat;
6225 int srcLeft, destLeft, destTop;
6226 WINED3DPOOL srcPool, destPool;
6228 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
6229 glDescriptor *glDescription = NULL;
6230 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
6234 CONVERT_TYPES convert = NO_CONVERSION;
6236 WINED3DSURFACE_DESC winedesc;
6238 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
6239 memset(&winedesc, 0, sizeof(winedesc));
6240 winedesc.Width = &srcSurfaceWidth;
6241 winedesc.Height = &srcSurfaceHeight;
6242 winedesc.Pool = &srcPool;
6243 winedesc.Format = &srcFormat;
6245 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
6247 winedesc.Width = &destSurfaceWidth;
6248 winedesc.Height = &destSurfaceHeight;
6249 winedesc.Pool = &destPool;
6250 winedesc.Format = &destFormat;
6251 winedesc.Size = &destSize;
6253 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6255 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
6256 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
6257 return WINED3DERR_INVALIDCALL;
6260 /* This call loads the opengl surface directly, instead of copying the surface to the
6261 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
6262 * copy in sysmem and use regular surface loading.
6264 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
6265 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
6266 if(convert != NO_CONVERSION) {
6267 return IWineD3DSurface_BltFast(pDestinationSurface,
6268 pDestPoint ? pDestPoint->x : 0,
6269 pDestPoint ? pDestPoint->y : 0,
6270 pSourceSurface, pSourceRect, 0);
6273 if (destFormat == WINED3DFMT_UNKNOWN) {
6274 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
6275 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
6277 /* Get the update surface description */
6278 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
6281 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6284 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6285 checkGLcall("glActiveTextureARB");
6288 /* Make sure the surface is loaded and up to date */
6289 surface_internal_preload(pDestinationSurface, SRGB_RGB);
6290 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
6292 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
6294 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
6295 dst_format_desc = ((IWineD3DSurfaceImpl *)pDestinationSurface)->resource.format_desc;
6297 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6298 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
6299 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
6300 srcLeft = pSourceRect ? pSourceRect->left : 0;
6301 destLeft = pDestPoint ? pDestPoint->x : 0;
6302 destTop = pDestPoint ? pDestPoint->y : 0;
6305 /* This function doesn't support compressed textures
6306 the pitch is just bytesPerPixel * width */
6307 if(srcWidth != srcSurfaceWidth || srcLeft ){
6308 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
6309 offset += srcLeft * src_format_desc->byte_count;
6310 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6312 /* TODO DXT formats */
6314 if(pSourceRect != NULL && pSourceRect->top != 0){
6315 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
6317 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
6318 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
6319 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
6322 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
6324 /* need to lock the surface to get the data */
6325 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6330 /* TODO: Cube and volume support */
6332 /* not a whole row so we have to do it a line at a time */
6335 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
6336 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6338 for (j = destTop; j < (srcHeight + destTop); ++j)
6340 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, j,
6341 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
6345 } else { /* Full width, so just write out the whole texture */
6346 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
6348 if (WINED3DFMT_DXT1 == destFormat ||
6349 WINED3DFMT_DXT2 == destFormat ||
6350 WINED3DFMT_DXT3 == destFormat ||
6351 WINED3DFMT_DXT4 == destFormat ||
6352 WINED3DFMT_DXT5 == destFormat) {
6353 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
6354 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
6355 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
6356 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6357 } if (destFormat != srcFormat) {
6358 FIXME("Updating mixed format compressed texture is not curretly support\n");
6360 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
6361 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
6364 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6369 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
6370 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
6373 checkGLcall("glTexSubImage2D");
6377 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
6378 sampler = This->rev_tex_unit_map[0];
6379 if (sampler != -1) {
6380 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6386 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6387 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6388 struct WineD3DRectPatch *patch;
6389 GLenum old_primitive_type;
6393 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6395 if(!(Handle || pRectPatchInfo)) {
6396 /* TODO: Write a test for the return value, thus the FIXME */
6397 FIXME("Both Handle and pRectPatchInfo are NULL\n");
6398 return WINED3DERR_INVALIDCALL;
6402 i = PATCHMAP_HASHFUNC(Handle);
6404 LIST_FOR_EACH(e, &This->patches[i]) {
6405 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6406 if(patch->Handle == Handle) {
6413 TRACE("Patch does not exist. Creating a new one\n");
6414 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6415 patch->Handle = Handle;
6416 list_add_head(&This->patches[i], &patch->entry);
6418 TRACE("Found existing patch %p\n", patch);
6421 /* Since opengl does not load tesselated vertex attributes into numbered vertex
6422 * attributes we have to tesselate, read back, and draw. This needs a patch
6423 * management structure instance. Create one.
6425 * A possible improvement is to check if a vertex shader is used, and if not directly
6428 FIXME("Drawing an uncached patch. This is slow\n");
6429 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6432 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
6433 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
6434 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
6436 TRACE("Tesselation density or patch info changed, retesselating\n");
6438 if(pRectPatchInfo) {
6439 patch->RectPatchInfo = *pRectPatchInfo;
6441 patch->numSegs[0] = pNumSegs[0];
6442 patch->numSegs[1] = pNumSegs[1];
6443 patch->numSegs[2] = pNumSegs[2];
6444 patch->numSegs[3] = pNumSegs[3];
6446 hr = tesselate_rectpatch(This, patch);
6448 WARN("Patch tesselation failed\n");
6450 /* Do not release the handle to store the params of the patch */
6452 HeapFree(GetProcessHeap(), 0, patch);
6458 This->currentPatch = patch;
6459 old_primitive_type = This->stateBlock->gl_primitive_type;
6460 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
6461 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
6462 This->stateBlock->gl_primitive_type = old_primitive_type;
6463 This->currentPatch = NULL;
6465 /* Destroy uncached patches */
6467 HeapFree(GetProcessHeap(), 0, patch->mem);
6468 HeapFree(GetProcessHeap(), 0, patch);
6473 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6474 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6475 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6476 FIXME("(%p) : Stub\n", This);
6480 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6481 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6483 struct WineD3DRectPatch *patch;
6485 TRACE("(%p) Handle(%d)\n", This, Handle);
6487 i = PATCHMAP_HASHFUNC(Handle);
6488 LIST_FOR_EACH(e, &This->patches[i]) {
6489 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6490 if(patch->Handle == Handle) {
6491 TRACE("Deleting patch %p\n", patch);
6492 list_remove(&patch->entry);
6493 HeapFree(GetProcessHeap(), 0, patch->mem);
6494 HeapFree(GetProcessHeap(), 0, patch);
6499 /* TODO: Write a test for the return value */
6500 FIXME("Attempt to destroy nonexistent patch\n");
6501 return WINED3DERR_INVALIDCALL;
6504 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6506 IWineD3DSwapChain *swapchain;
6508 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6509 if (SUCCEEDED(hr)) {
6510 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6517 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
6518 const WINED3DRECT *rect, const float color[4])
6520 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6521 IWineD3DSwapChain *swapchain;
6523 swapchain = get_swapchain(surface);
6527 TRACE("Surface %p is onscreen\n", surface);
6529 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6531 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6532 buffer = surface_get_gl_buffer(surface, swapchain);
6533 glDrawBuffer(buffer);
6534 checkGLcall("glDrawBuffer()");
6536 TRACE("Surface %p is offscreen\n", surface);
6538 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6540 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6541 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6542 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6543 checkGLcall("glFramebufferRenderbufferEXT");
6547 glEnable(GL_SCISSOR_TEST);
6549 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6551 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6552 rect->x2 - rect->x1, rect->y2 - rect->y1);
6554 checkGLcall("glScissor");
6555 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6557 glDisable(GL_SCISSOR_TEST);
6559 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6561 glDisable(GL_BLEND);
6562 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6564 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6565 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6567 glClearColor(color[0], color[1], color[2], color[3]);
6568 glClear(GL_COLOR_BUFFER_BIT);
6569 checkGLcall("glClear");
6571 if (This->activeContext->current_fbo) {
6572 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6574 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6575 checkGLcall("glBindFramebuffer()");
6578 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6579 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6580 glDrawBuffer(GL_BACK);
6581 checkGLcall("glDrawBuffer()");
6587 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6588 unsigned int r, g, b, a;
6591 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6592 destfmt == WINED3DFMT_R8G8B8)
6595 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6597 a = (color & 0xff000000) >> 24;
6598 r = (color & 0x00ff0000) >> 16;
6599 g = (color & 0x0000ff00) >> 8;
6600 b = (color & 0x000000ff) >> 0;
6604 case WINED3DFMT_R5G6B5:
6605 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6612 TRACE("Returning %08x\n", ret);
6615 case WINED3DFMT_X1R5G5B5:
6616 case WINED3DFMT_A1R5G5B5:
6625 TRACE("Returning %08x\n", ret);
6628 case WINED3DFMT_A8_UNORM:
6629 TRACE("Returning %08x\n", a);
6632 case WINED3DFMT_X4R4G4B4:
6633 case WINED3DFMT_A4R4G4B4:
6642 TRACE("Returning %08x\n", ret);
6645 case WINED3DFMT_R3G3B2:
6652 TRACE("Returning %08x\n", ret);
6655 case WINED3DFMT_X8B8G8R8:
6656 case WINED3DFMT_R8G8B8A8_UNORM:
6661 TRACE("Returning %08x\n", ret);
6664 case WINED3DFMT_A2R10G10B10:
6666 r = (r * 1024) / 256;
6667 g = (g * 1024) / 256;
6668 b = (b * 1024) / 256;
6673 TRACE("Returning %08x\n", ret);
6676 case WINED3DFMT_R10G10B10A2_UNORM:
6678 r = (r * 1024) / 256;
6679 g = (g * 1024) / 256;
6680 b = (b * 1024) / 256;
6685 TRACE("Returning %08x\n", ret);
6689 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6694 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6695 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6696 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6698 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6700 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6701 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6702 return WINED3DERR_INVALIDCALL;
6705 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6706 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
6707 color_fill_fbo(iface, pSurface, pRect, c);
6710 /* Just forward this to the DirectDraw blitting engine */
6711 memset(&BltFx, 0, sizeof(BltFx));
6712 BltFx.dwSize = sizeof(BltFx);
6713 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
6714 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6715 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6719 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
6720 IWineD3DRendertargetView *rendertarget_view, const float color[4])
6722 IWineD3DResource *resource;
6723 IWineD3DSurface *surface;
6726 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
6729 ERR("Failed to get resource, hr %#x\n", hr);
6733 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
6735 FIXME("Only supported on surface resources\n");
6736 IWineD3DResource_Release(resource);
6740 surface = (IWineD3DSurface *)resource;
6742 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6744 color_fill_fbo(iface, surface, NULL, color);
6751 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
6753 c = ((DWORD)(color[2] * 255.0));
6754 c |= ((DWORD)(color[1] * 255.0)) << 8;
6755 c |= ((DWORD)(color[0] * 255.0)) << 16;
6756 c |= ((DWORD)(color[3] * 255.0)) << 24;
6758 /* Just forward this to the DirectDraw blitting engine */
6759 memset(&BltFx, 0, sizeof(BltFx));
6760 BltFx.dwSize = sizeof(BltFx);
6761 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
6762 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6765 ERR("Blt failed, hr %#x\n", hr);
6769 IWineD3DResource_Release(resource);
6772 /* rendertarget and depth stencil functions */
6773 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6774 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6776 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6777 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6778 return WINED3DERR_INVALIDCALL;
6781 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6782 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6783 /* Note inc ref on returned surface */
6784 if(*ppRenderTarget != NULL)
6785 IWineD3DSurface_AddRef(*ppRenderTarget);
6789 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6790 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6791 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6792 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6793 IWineD3DSwapChainImpl *Swapchain;
6796 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6798 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6799 if(hr != WINED3D_OK) {
6800 ERR("Can't get the swapchain\n");
6804 /* Make sure to release the swapchain */
6805 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6807 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6808 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6809 return WINED3DERR_INVALIDCALL;
6811 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6812 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6813 return WINED3DERR_INVALIDCALL;
6816 if(Swapchain->frontBuffer != Front) {
6817 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6819 if(Swapchain->frontBuffer)
6821 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6822 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
6824 Swapchain->frontBuffer = Front;
6826 if(Swapchain->frontBuffer) {
6827 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6828 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
6832 if(Back && !Swapchain->backBuffer) {
6833 /* We need memory for the back buffer array - only one back buffer this way */
6834 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6835 if(!Swapchain->backBuffer) {
6836 ERR("Out of memory\n");
6837 return E_OUTOFMEMORY;
6841 if(Swapchain->backBuffer[0] != Back) {
6842 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6844 /* What to do about the context here in the case of multithreading? Not sure.
6845 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6848 if(!Swapchain->backBuffer[0]) {
6849 /* GL was told to draw to the front buffer at creation,
6852 glDrawBuffer(GL_BACK);
6853 checkGLcall("glDrawBuffer(GL_BACK)");
6854 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6855 Swapchain->presentParms.BackBufferCount = 1;
6857 /* That makes problems - disable for now */
6858 /* glDrawBuffer(GL_FRONT); */
6859 checkGLcall("glDrawBuffer(GL_FRONT)");
6860 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6861 Swapchain->presentParms.BackBufferCount = 0;
6865 if(Swapchain->backBuffer[0])
6867 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6868 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
6870 Swapchain->backBuffer[0] = Back;
6872 if(Swapchain->backBuffer[0]) {
6873 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6874 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
6876 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6877 Swapchain->backBuffer = NULL;
6885 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6886 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6887 *ppZStencilSurface = This->stencilBufferTarget;
6888 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6890 if(*ppZStencilSurface != NULL) {
6891 /* Note inc ref on returned surface */
6892 IWineD3DSurface_AddRef(*ppZStencilSurface);
6895 return WINED3DERR_NOTFOUND;
6899 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6900 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6902 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6903 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6904 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6906 POINT offset = {0, 0};
6908 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6909 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6910 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6911 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6914 case WINED3DTEXF_LINEAR:
6915 gl_filter = GL_LINEAR;
6919 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6920 case WINED3DTEXF_NONE:
6921 case WINED3DTEXF_POINT:
6922 gl_filter = GL_NEAREST;
6926 /* Attach src surface to src fbo */
6927 src_swapchain = get_swapchain(src_surface);
6928 if (src_swapchain) {
6929 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6931 TRACE("Source surface %p is onscreen\n", src_surface);
6932 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6933 /* Make sure the drawable is up to date. In the offscreen case
6934 * attach_surface_fbo() implicitly takes care of this. */
6935 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6937 if(buffer == GL_FRONT) {
6940 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6941 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6942 h = windowsize.bottom - windowsize.top;
6943 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6944 src_rect->y1 = offset.y + h - src_rect->y1;
6945 src_rect->y2 = offset.y + h - src_rect->y2;
6947 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6948 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6952 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6953 glReadBuffer(buffer);
6954 checkGLcall("glReadBuffer()");
6956 TRACE("Source surface %p is offscreen\n", src_surface);
6958 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6959 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6960 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6961 checkGLcall("glReadBuffer()");
6962 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6963 checkGLcall("glFramebufferRenderbufferEXT");
6967 /* Attach dst surface to dst fbo */
6968 dst_swapchain = get_swapchain(dst_surface);
6969 if (dst_swapchain) {
6970 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6972 TRACE("Destination surface %p is onscreen\n", dst_surface);
6973 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6974 /* Make sure the drawable is up to date. In the offscreen case
6975 * attach_surface_fbo() implicitly takes care of this. */
6976 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6978 if(buffer == GL_FRONT) {
6981 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6982 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6983 h = windowsize.bottom - windowsize.top;
6984 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6985 dst_rect->y1 = offset.y + h - dst_rect->y1;
6986 dst_rect->y2 = offset.y + h - dst_rect->y2;
6988 /* Screen coords = window coords, surface height = window height */
6989 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6990 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6994 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6995 glDrawBuffer(buffer);
6996 checkGLcall("glDrawBuffer()");
6998 TRACE("Destination surface %p is offscreen\n", dst_surface);
7000 /* No src or dst swapchain? Make sure some context is active(multithreading) */
7001 if(!src_swapchain) {
7002 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7006 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
7007 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
7008 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
7009 checkGLcall("glDrawBuffer()");
7010 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
7011 checkGLcall("glFramebufferRenderbufferEXT");
7013 glDisable(GL_SCISSOR_TEST);
7014 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
7017 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
7018 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
7019 checkGLcall("glBlitFramebuffer()");
7021 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
7022 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
7023 checkGLcall("glBlitFramebuffer()");
7026 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
7028 if (This->activeContext->current_fbo) {
7029 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
7031 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
7032 checkGLcall("glBindFramebuffer()");
7035 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
7036 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
7037 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
7038 glDrawBuffer(GL_BACK);
7039 checkGLcall("glDrawBuffer()");
7044 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
7045 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7046 WINED3DVIEWPORT viewport;
7048 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
7050 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
7051 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
7052 This, RenderTargetIndex, GL_LIMITS(buffers));
7053 return WINED3DERR_INVALIDCALL;
7056 /* MSDN says that null disables the render target
7057 but a device must always be associated with a render target
7058 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
7060 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
7061 FIXME("Trying to set render target 0 to NULL\n");
7062 return WINED3DERR_INVALIDCALL;
7064 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
7065 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);
7066 return WINED3DERR_INVALIDCALL;
7069 /* If we are trying to set what we already have, don't bother */
7070 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
7071 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7074 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
7075 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
7076 This->render_targets[RenderTargetIndex] = pRenderTarget;
7078 /* Render target 0 is special */
7079 if(RenderTargetIndex == 0) {
7080 /* Finally, reset the viewport as the MSDN states. */
7081 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
7082 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
7085 viewport.MaxZ = 1.0f;
7086 viewport.MinZ = 0.0f;
7087 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
7088 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
7089 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
7091 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
7096 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
7097 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7098 HRESULT hr = WINED3D_OK;
7099 IWineD3DSurface *tmp;
7101 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
7103 if (pNewZStencil == This->stencilBufferTarget) {
7104 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7106 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
7107 * depending on the renter target implementation being used.
7108 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
7109 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7110 * stencil buffer and incur an extra memory overhead
7111 ******************************************************/
7113 if (This->stencilBufferTarget) {
7114 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
7115 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
7116 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
7118 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
7119 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
7120 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
7124 tmp = This->stencilBufferTarget;
7125 This->stencilBufferTarget = pNewZStencil;
7126 /* should we be calling the parent or the wined3d surface? */
7127 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
7128 if (NULL != tmp) IWineD3DSurface_Release(tmp);
7131 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
7132 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
7133 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
7134 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
7135 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
7142 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
7143 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
7144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7145 /* TODO: the use of Impl is deprecated. */
7146 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
7147 WINED3DLOCKED_RECT lockedRect;
7149 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
7151 /* some basic validation checks */
7152 if(This->cursorTexture) {
7153 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7155 glDeleteTextures(1, &This->cursorTexture);
7157 This->cursorTexture = 0;
7160 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
7161 This->haveHardwareCursor = TRUE;
7163 This->haveHardwareCursor = FALSE;
7166 WINED3DLOCKED_RECT rect;
7168 /* MSDN: Cursor must be A8R8G8B8 */
7169 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format_desc->format)
7171 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
7172 return WINED3DERR_INVALIDCALL;
7175 /* MSDN: Cursor must be smaller than the display mode */
7176 if(pSur->currentDesc.Width > This->ddraw_width ||
7177 pSur->currentDesc.Height > This->ddraw_height) {
7178 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);
7179 return WINED3DERR_INVALIDCALL;
7182 if (!This->haveHardwareCursor) {
7183 /* TODO: MSDN: Cursor sizes must be a power of 2 */
7185 /* Do not store the surface's pointer because the application may
7186 * release it after setting the cursor image. Windows doesn't
7187 * addref the set surface, so we can't do this either without
7188 * creating circular refcount dependencies. Copy out the gl texture
7191 This->cursorWidth = pSur->currentDesc.Width;
7192 This->cursorHeight = pSur->currentDesc.Height;
7193 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
7195 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION);
7196 char *mem, *bits = rect.pBits;
7197 GLint intfmt = glDesc->glInternal;
7198 GLint format = glDesc->glFormat;
7199 GLint type = glDesc->glType;
7200 INT height = This->cursorHeight;
7201 INT width = This->cursorWidth;
7202 INT bpp = glDesc->byte_count;
7205 /* Reformat the texture memory (pitch and width can be
7207 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
7208 for(i = 0; i < height; i++)
7209 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
7210 IWineD3DSurface_UnlockRect(pCursorBitmap);
7213 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
7214 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
7215 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
7218 /* Make sure that a proper texture unit is selected */
7219 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
7220 checkGLcall("glActiveTextureARB");
7221 sampler = This->rev_tex_unit_map[0];
7222 if (sampler != -1) {
7223 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
7225 /* Create a new cursor texture */
7226 glGenTextures(1, &This->cursorTexture);
7227 checkGLcall("glGenTextures");
7228 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
7229 checkGLcall("glBindTexture");
7230 /* Copy the bitmap memory into the cursor texture */
7231 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
7232 HeapFree(GetProcessHeap(), 0, mem);
7233 checkGLcall("glTexImage2D");
7235 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
7236 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
7237 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
7244 FIXME("A cursor texture was not returned.\n");
7245 This->cursorTexture = 0;
7250 /* Draw a hardware cursor */
7251 ICONINFO cursorInfo;
7253 /* Create and clear maskBits because it is not needed for
7254 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
7256 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
7257 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
7258 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
7259 WINED3DLOCK_NO_DIRTY_UPDATE |
7260 WINED3DLOCK_READONLY
7262 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
7263 pSur->currentDesc.Height);
7265 cursorInfo.fIcon = FALSE;
7266 cursorInfo.xHotspot = XHotSpot;
7267 cursorInfo.yHotspot = YHotSpot;
7268 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
7269 pSur->currentDesc.Height, 1,
7271 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
7272 pSur->currentDesc.Height, 1,
7273 32, lockedRect.pBits);
7274 IWineD3DSurface_UnlockRect(pCursorBitmap);
7275 /* Create our cursor and clean up. */
7276 cursor = CreateIconIndirect(&cursorInfo);
7278 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
7279 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
7280 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
7281 This->hardwareCursor = cursor;
7282 HeapFree(GetProcessHeap(), 0, maskBits);
7286 This->xHotSpot = XHotSpot;
7287 This->yHotSpot = YHotSpot;
7291 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7292 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7293 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7295 This->xScreenSpace = XScreenSpace;
7296 This->yScreenSpace = YScreenSpace;
7302 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7304 BOOL oldVisible = This->bCursorVisible;
7307 TRACE("(%p) : visible(%d)\n", This, bShow);
7310 * When ShowCursor is first called it should make the cursor appear at the OS's last
7311 * known cursor position. Because of this, some applications just repetitively call
7312 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
7315 This->xScreenSpace = pt.x;
7316 This->yScreenSpace = pt.y;
7318 if (This->haveHardwareCursor) {
7319 This->bCursorVisible = bShow;
7321 SetCursor(This->hardwareCursor);
7327 if (This->cursorTexture)
7328 This->bCursorVisible = bShow;
7334 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7335 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7336 IWineD3DResourceImpl *resource;
7337 TRACE("(%p) : state (%u)\n", This, This->state);
7339 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
7340 switch (This->state) {
7343 case WINED3DERR_DEVICELOST:
7345 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7346 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
7347 return WINED3DERR_DEVICENOTRESET;
7349 return WINED3DERR_DEVICELOST;
7351 case WINED3DERR_DRIVERINTERNALERROR:
7352 return WINED3DERR_DRIVERINTERNALERROR;
7356 return WINED3DERR_DRIVERINTERNALERROR;
7360 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7361 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7362 /** FIXME: Resource tracking needs to be done,
7363 * The closes we can do to this is set the priorities of all managed textures low
7364 * and then reset them.
7365 ***********************************************************/
7366 FIXME("(%p) : stub\n", This);
7370 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
7372 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
7374 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7375 if(surface->Flags & SFLAG_DIBSECTION) {
7376 /* Release the DC */
7377 SelectObject(surface->hDC, surface->dib.holdbitmap);
7378 DeleteDC(surface->hDC);
7379 /* Release the DIB section */
7380 DeleteObject(surface->dib.DIBsection);
7381 surface->dib.bitmap_data = NULL;
7382 surface->resource.allocatedMemory = NULL;
7383 surface->Flags &= ~SFLAG_DIBSECTION;
7385 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7386 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7387 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
7388 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
7389 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7390 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7392 surface->pow2Width = surface->pow2Height = 1;
7393 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7394 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7396 surface->glRect.left = 0;
7397 surface->glRect.top = 0;
7398 surface->glRect.right = surface->pow2Width;
7399 surface->glRect.bottom = surface->pow2Height;
7401 if(surface->glDescription.textureName) {
7402 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7404 glDeleteTextures(1, &surface->glDescription.textureName);
7406 surface->glDescription.textureName = 0;
7407 surface->Flags &= ~SFLAG_CLIENT;
7409 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7410 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7411 surface->Flags |= SFLAG_NONPOW2;
7413 surface->Flags &= ~SFLAG_NONPOW2;
7415 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7416 surface->resource.allocatedMemory = NULL;
7417 surface->resource.heapMemory = NULL;
7418 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7419 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7420 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7421 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7423 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7427 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7428 TRACE("Unloading resource %p\n", resource);
7429 IWineD3DResource_UnLoad(resource);
7430 IWineD3DResource_Release(resource);
7434 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
7437 WINED3DDISPLAYMODE m;
7440 /* All Windowed modes are supported, as is leaving the current mode */
7441 if(pp->Windowed) return TRUE;
7442 if(!pp->BackBufferWidth) return TRUE;
7443 if(!pp->BackBufferHeight) return TRUE;
7445 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7446 for(i = 0; i < count; i++) {
7447 memset(&m, 0, sizeof(m));
7448 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7450 ERR("EnumAdapterModes failed\n");
7452 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7453 /* Mode found, it is supported */
7457 /* Mode not found -> not supported */
7461 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7462 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7463 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7465 IWineD3DBaseShaderImpl *shader;
7467 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7468 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7469 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7473 if(This->depth_blt_texture) {
7474 glDeleteTextures(1, &This->depth_blt_texture);
7475 This->depth_blt_texture = 0;
7477 if (This->depth_blt_rb) {
7478 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7479 This->depth_blt_rb = 0;
7480 This->depth_blt_rb_w = 0;
7481 This->depth_blt_rb_h = 0;
7485 This->blitter->free_private(iface);
7486 This->frag_pipe->free_private(iface);
7487 This->shader_backend->shader_free_private(iface);
7490 for (i = 0; i < GL_LIMITS(textures); i++) {
7491 /* Textures are recreated below */
7492 glDeleteTextures(1, &This->dummyTextureName[i]);
7493 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7494 This->dummyTextureName[i] = 0;
7498 while(This->numContexts) {
7499 DestroyContext(This, This->contexts[0]);
7501 This->activeContext = NULL;
7502 HeapFree(GetProcessHeap(), 0, swapchain->context);
7503 swapchain->context = NULL;
7504 swapchain->num_contexts = 0;
7507 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7508 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7509 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7511 IWineD3DSurfaceImpl *target;
7513 /* Recreate the primary swapchain's context */
7514 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7515 if(swapchain->backBuffer) {
7516 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7518 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7520 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7521 &swapchain->presentParms);
7522 swapchain->num_contexts = 1;
7523 This->activeContext = swapchain->context[0];
7525 create_dummy_textures(This);
7527 hr = This->shader_backend->shader_alloc_private(iface);
7529 ERR("Failed to recreate shader private data\n");
7532 hr = This->frag_pipe->alloc_private(iface);
7534 TRACE("Fragment pipeline private data couldn't be allocated\n");
7537 hr = This->blitter->alloc_private(iface);
7539 TRACE("Blitter private data couldn't be allocated\n");
7546 This->blitter->free_private(iface);
7547 This->frag_pipe->free_private(iface);
7548 This->shader_backend->shader_free_private(iface);
7552 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7553 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7554 IWineD3DSwapChainImpl *swapchain;
7556 BOOL DisplayModeChanged = FALSE;
7557 WINED3DDISPLAYMODE mode;
7558 TRACE("(%p)\n", This);
7560 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7562 ERR("Failed to get the first implicit swapchain\n");
7566 if(!is_display_mode_supported(This, pPresentationParameters)) {
7567 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7568 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7569 pPresentationParameters->BackBufferHeight);
7570 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
7571 return WINED3DERR_INVALIDCALL;
7574 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7575 * on an existing gl context, so there's no real need for recreation.
7577 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7579 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7581 TRACE("New params:\n");
7582 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7583 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7584 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7585 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7586 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7587 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7588 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7589 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7590 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7591 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7592 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7593 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7594 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7596 /* No special treatment of these parameters. Just store them */
7597 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7598 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7599 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7600 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7602 /* What to do about these? */
7603 if(pPresentationParameters->BackBufferCount != 0 &&
7604 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7605 ERR("Cannot change the back buffer count yet\n");
7607 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7608 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7609 ERR("Cannot change the back buffer format yet\n");
7611 if(pPresentationParameters->hDeviceWindow != NULL &&
7612 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7613 ERR("Cannot change the device window yet\n");
7615 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7616 WARN("Auto depth stencil enabled, but no auto depth stencil present, returning WINED3DERR_INVALIDCALL\n");
7617 return WINED3DERR_INVALIDCALL;
7620 /* Reset the depth stencil */
7621 if (pPresentationParameters->EnableAutoDepthStencil)
7622 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7624 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7626 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7628 if(pPresentationParameters->Windowed) {
7629 mode.Width = swapchain->orig_width;
7630 mode.Height = swapchain->orig_height;
7631 mode.RefreshRate = 0;
7632 mode.Format = swapchain->presentParms.BackBufferFormat;
7634 mode.Width = pPresentationParameters->BackBufferWidth;
7635 mode.Height = pPresentationParameters->BackBufferHeight;
7636 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7637 mode.Format = swapchain->presentParms.BackBufferFormat;
7640 /* Should Width == 800 && Height == 0 set 800x600? */
7641 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7642 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7643 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7647 if(!pPresentationParameters->Windowed) {
7648 DisplayModeChanged = TRUE;
7650 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7651 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7653 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7654 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7655 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7657 if(This->auto_depth_stencil_buffer) {
7658 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7662 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7663 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7664 DisplayModeChanged) {
7666 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7668 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7669 if(swapchain->presentParms.Windowed) {
7670 /* switch from windowed to fs */
7671 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7672 pPresentationParameters->BackBufferWidth,
7673 pPresentationParameters->BackBufferHeight);
7675 /* Fullscreen -> fullscreen mode change */
7676 MoveWindow(swapchain->win_handle, 0, 0,
7677 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7680 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7681 /* Fullscreen -> windowed switch */
7682 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7684 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7685 } else if(!pPresentationParameters->Windowed) {
7686 DWORD style = This->style, exStyle = This->exStyle;
7687 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7688 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7689 * Reset to clear up their mess. Guild Wars also loses the device during that.
7693 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7694 pPresentationParameters->BackBufferWidth,
7695 pPresentationParameters->BackBufferHeight);
7696 This->style = style;
7697 This->exStyle = exStyle;
7700 TRACE("Resetting stateblock\n");
7701 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
7702 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
7704 /* Note: No parent needed for initial internal stateblock */
7705 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
7706 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7707 else TRACE("Created stateblock %p\n", This->stateBlock);
7708 This->updateStateBlock = This->stateBlock;
7709 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
7711 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7713 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7716 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7717 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7719 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7725 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7726 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7727 /** FIXME: always true at the moment **/
7728 if(!bEnableDialogs) {
7729 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7735 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7736 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7737 TRACE("(%p) : pParameters %p\n", This, pParameters);
7739 *pParameters = This->createParms;
7743 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7744 IWineD3DSwapChain *swapchain;
7746 TRACE("Relaying to swapchain\n");
7748 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7749 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7750 IWineD3DSwapChain_Release(swapchain);
7755 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7756 IWineD3DSwapChain *swapchain;
7758 TRACE("Relaying to swapchain\n");
7760 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7761 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7762 IWineD3DSwapChain_Release(swapchain);
7768 /** ********************************************************
7769 * Notification functions
7770 ** ********************************************************/
7771 /** This function must be called in the release of a resource when ref == 0,
7772 * the contents of resource must still be correct,
7773 * any handles to other resource held by the caller must be closed
7774 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7775 *****************************************************/
7776 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7777 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7779 TRACE("(%p) : Adding Resource %p\n", This, resource);
7780 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7783 static void IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7784 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7786 TRACE("(%p) : Removing resource %p\n", This, resource);
7788 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7792 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7793 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7794 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7797 TRACE("(%p) : resource %p\n", This, resource);
7799 context_resource_released(iface, resource, type);
7802 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7803 case WINED3DRTYPE_SURFACE: {
7806 /* Cleanup any FBO attachments if d3d is enabled */
7807 if(This->d3d_initialized) {
7808 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7809 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7811 TRACE("Last active render target destroyed\n");
7812 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7813 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7814 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7815 * and the lastActiveRenderTarget member shouldn't matter
7818 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7819 TRACE("Activating primary back buffer\n");
7820 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7821 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7822 /* Single buffering environment */
7823 TRACE("Activating primary front buffer\n");
7824 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7826 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7827 /* Implicit render target destroyed, that means the device is being destroyed
7828 * whatever we set here, it shouldn't matter
7830 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7833 /* May happen during ddraw uninitialization */
7834 TRACE("Render target set, but swapchain does not exist!\n");
7835 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7839 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7840 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7841 This->render_targets[i] = NULL;
7844 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7845 This->stencilBufferTarget = NULL;
7851 case WINED3DRTYPE_TEXTURE:
7852 case WINED3DRTYPE_CUBETEXTURE:
7853 case WINED3DRTYPE_VOLUMETEXTURE:
7854 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7855 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7856 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7857 This->stateBlock->textures[counter] = NULL;
7859 if (This->updateStateBlock != This->stateBlock ){
7860 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7861 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7862 This->updateStateBlock->textures[counter] = NULL;
7867 case WINED3DRTYPE_VOLUME:
7868 /* TODO: nothing really? */
7870 case WINED3DRTYPE_BUFFER:
7873 TRACE("Cleaning up stream pointers\n");
7875 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7876 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7877 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7879 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7880 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7881 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7882 This->updateStateBlock->streamSource[streamNumber] = 0;
7883 /* Set changed flag? */
7886 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) */
7887 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7888 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7889 This->stateBlock->streamSource[streamNumber] = 0;
7894 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7895 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7896 This->updateStateBlock->pIndexData = NULL;
7899 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7900 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7901 This->stateBlock->pIndexData = NULL;
7908 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7913 /* Remove the resource from the resourceStore */
7914 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7916 TRACE("Resource released\n");
7920 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7921 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7922 IWineD3DResourceImpl *resource, *cursor;
7924 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7926 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7927 TRACE("enumerating resource %p\n", resource);
7928 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7929 ret = pCallback((IWineD3DResource *) resource, pData);
7930 if(ret == S_FALSE) {
7931 TRACE("Canceling enumeration\n");
7938 /**********************************************************
7939 * IWineD3DDevice VTbl follows
7940 **********************************************************/
7942 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7944 /*** IUnknown methods ***/
7945 IWineD3DDeviceImpl_QueryInterface,
7946 IWineD3DDeviceImpl_AddRef,
7947 IWineD3DDeviceImpl_Release,
7948 /*** IWineD3DDevice methods ***/
7949 IWineD3DDeviceImpl_GetParent,
7950 /*** Creation methods**/
7951 IWineD3DDeviceImpl_CreateBuffer,
7952 IWineD3DDeviceImpl_CreateVertexBuffer,
7953 IWineD3DDeviceImpl_CreateIndexBuffer,
7954 IWineD3DDeviceImpl_CreateStateBlock,
7955 IWineD3DDeviceImpl_CreateSurface,
7956 IWineD3DDeviceImpl_CreateRendertargetView,
7957 IWineD3DDeviceImpl_CreateTexture,
7958 IWineD3DDeviceImpl_CreateVolumeTexture,
7959 IWineD3DDeviceImpl_CreateVolume,
7960 IWineD3DDeviceImpl_CreateCubeTexture,
7961 IWineD3DDeviceImpl_CreateQuery,
7962 IWineD3DDeviceImpl_CreateSwapChain,
7963 IWineD3DDeviceImpl_CreateVertexDeclaration,
7964 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7965 IWineD3DDeviceImpl_CreateVertexShader,
7966 IWineD3DDeviceImpl_CreatePixelShader,
7967 IWineD3DDeviceImpl_CreatePalette,
7968 /*** Odd functions **/
7969 IWineD3DDeviceImpl_Init3D,
7970 IWineD3DDeviceImpl_InitGDI,
7971 IWineD3DDeviceImpl_Uninit3D,
7972 IWineD3DDeviceImpl_UninitGDI,
7973 IWineD3DDeviceImpl_SetMultithreaded,
7974 IWineD3DDeviceImpl_EvictManagedResources,
7975 IWineD3DDeviceImpl_GetAvailableTextureMem,
7976 IWineD3DDeviceImpl_GetBackBuffer,
7977 IWineD3DDeviceImpl_GetCreationParameters,
7978 IWineD3DDeviceImpl_GetDeviceCaps,
7979 IWineD3DDeviceImpl_GetDirect3D,
7980 IWineD3DDeviceImpl_GetDisplayMode,
7981 IWineD3DDeviceImpl_SetDisplayMode,
7982 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7983 IWineD3DDeviceImpl_GetRasterStatus,
7984 IWineD3DDeviceImpl_GetSwapChain,
7985 IWineD3DDeviceImpl_Reset,
7986 IWineD3DDeviceImpl_SetDialogBoxMode,
7987 IWineD3DDeviceImpl_SetCursorProperties,
7988 IWineD3DDeviceImpl_SetCursorPosition,
7989 IWineD3DDeviceImpl_ShowCursor,
7990 IWineD3DDeviceImpl_TestCooperativeLevel,
7991 /*** Getters and setters **/
7992 IWineD3DDeviceImpl_SetClipPlane,
7993 IWineD3DDeviceImpl_GetClipPlane,
7994 IWineD3DDeviceImpl_SetClipStatus,
7995 IWineD3DDeviceImpl_GetClipStatus,
7996 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7997 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7998 IWineD3DDeviceImpl_SetDepthStencilSurface,
7999 IWineD3DDeviceImpl_GetDepthStencilSurface,
8000 IWineD3DDeviceImpl_SetGammaRamp,
8001 IWineD3DDeviceImpl_GetGammaRamp,
8002 IWineD3DDeviceImpl_SetIndices,
8003 IWineD3DDeviceImpl_GetIndices,
8004 IWineD3DDeviceImpl_SetBaseVertexIndex,
8005 IWineD3DDeviceImpl_GetBaseVertexIndex,
8006 IWineD3DDeviceImpl_SetLight,
8007 IWineD3DDeviceImpl_GetLight,
8008 IWineD3DDeviceImpl_SetLightEnable,
8009 IWineD3DDeviceImpl_GetLightEnable,
8010 IWineD3DDeviceImpl_SetMaterial,
8011 IWineD3DDeviceImpl_GetMaterial,
8012 IWineD3DDeviceImpl_SetNPatchMode,
8013 IWineD3DDeviceImpl_GetNPatchMode,
8014 IWineD3DDeviceImpl_SetPaletteEntries,
8015 IWineD3DDeviceImpl_GetPaletteEntries,
8016 IWineD3DDeviceImpl_SetPixelShader,
8017 IWineD3DDeviceImpl_GetPixelShader,
8018 IWineD3DDeviceImpl_SetPixelShaderConstantB,
8019 IWineD3DDeviceImpl_GetPixelShaderConstantB,
8020 IWineD3DDeviceImpl_SetPixelShaderConstantI,
8021 IWineD3DDeviceImpl_GetPixelShaderConstantI,
8022 IWineD3DDeviceImpl_SetPixelShaderConstantF,
8023 IWineD3DDeviceImpl_GetPixelShaderConstantF,
8024 IWineD3DDeviceImpl_SetRenderState,
8025 IWineD3DDeviceImpl_GetRenderState,
8026 IWineD3DDeviceImpl_SetRenderTarget,
8027 IWineD3DDeviceImpl_GetRenderTarget,
8028 IWineD3DDeviceImpl_SetFrontBackBuffers,
8029 IWineD3DDeviceImpl_SetSamplerState,
8030 IWineD3DDeviceImpl_GetSamplerState,
8031 IWineD3DDeviceImpl_SetScissorRect,
8032 IWineD3DDeviceImpl_GetScissorRect,
8033 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
8034 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
8035 IWineD3DDeviceImpl_SetStreamSource,
8036 IWineD3DDeviceImpl_GetStreamSource,
8037 IWineD3DDeviceImpl_SetStreamSourceFreq,
8038 IWineD3DDeviceImpl_GetStreamSourceFreq,
8039 IWineD3DDeviceImpl_SetTexture,
8040 IWineD3DDeviceImpl_GetTexture,
8041 IWineD3DDeviceImpl_SetTextureStageState,
8042 IWineD3DDeviceImpl_GetTextureStageState,
8043 IWineD3DDeviceImpl_SetTransform,
8044 IWineD3DDeviceImpl_GetTransform,
8045 IWineD3DDeviceImpl_SetVertexDeclaration,
8046 IWineD3DDeviceImpl_GetVertexDeclaration,
8047 IWineD3DDeviceImpl_SetVertexShader,
8048 IWineD3DDeviceImpl_GetVertexShader,
8049 IWineD3DDeviceImpl_SetVertexShaderConstantB,
8050 IWineD3DDeviceImpl_GetVertexShaderConstantB,
8051 IWineD3DDeviceImpl_SetVertexShaderConstantI,
8052 IWineD3DDeviceImpl_GetVertexShaderConstantI,
8053 IWineD3DDeviceImpl_SetVertexShaderConstantF,
8054 IWineD3DDeviceImpl_GetVertexShaderConstantF,
8055 IWineD3DDeviceImpl_SetViewport,
8056 IWineD3DDeviceImpl_GetViewport,
8057 IWineD3DDeviceImpl_MultiplyTransform,
8058 IWineD3DDeviceImpl_ValidateDevice,
8059 IWineD3DDeviceImpl_ProcessVertices,
8060 /*** State block ***/
8061 IWineD3DDeviceImpl_BeginStateBlock,
8062 IWineD3DDeviceImpl_EndStateBlock,
8063 /*** Scene management ***/
8064 IWineD3DDeviceImpl_BeginScene,
8065 IWineD3DDeviceImpl_EndScene,
8066 IWineD3DDeviceImpl_Present,
8067 IWineD3DDeviceImpl_Clear,
8068 IWineD3DDeviceImpl_ClearRendertargetView,
8070 IWineD3DDeviceImpl_SetPrimitiveType,
8071 IWineD3DDeviceImpl_GetPrimitiveType,
8072 IWineD3DDeviceImpl_DrawPrimitive,
8073 IWineD3DDeviceImpl_DrawIndexedPrimitive,
8074 IWineD3DDeviceImpl_DrawPrimitiveUP,
8075 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
8076 IWineD3DDeviceImpl_DrawPrimitiveStrided,
8077 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
8078 IWineD3DDeviceImpl_DrawRectPatch,
8079 IWineD3DDeviceImpl_DrawTriPatch,
8080 IWineD3DDeviceImpl_DeletePatch,
8081 IWineD3DDeviceImpl_ColorFill,
8082 IWineD3DDeviceImpl_UpdateTexture,
8083 IWineD3DDeviceImpl_UpdateSurface,
8084 IWineD3DDeviceImpl_GetFrontBufferData,
8085 /*** object tracking ***/
8086 IWineD3DDeviceImpl_ResourceReleased,
8087 IWineD3DDeviceImpl_EnumResources
8090 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
8091 WINED3DRS_ALPHABLENDENABLE ,
8092 WINED3DRS_ALPHAFUNC ,
8093 WINED3DRS_ALPHAREF ,
8094 WINED3DRS_ALPHATESTENABLE ,
8096 WINED3DRS_COLORWRITEENABLE ,
8097 WINED3DRS_DESTBLEND ,
8098 WINED3DRS_DITHERENABLE ,
8099 WINED3DRS_FILLMODE ,
8100 WINED3DRS_FOGDENSITY ,
8102 WINED3DRS_FOGSTART ,
8103 WINED3DRS_LASTPIXEL ,
8104 WINED3DRS_SHADEMODE ,
8105 WINED3DRS_SRCBLEND ,
8106 WINED3DRS_STENCILENABLE ,
8107 WINED3DRS_STENCILFAIL ,
8108 WINED3DRS_STENCILFUNC ,
8109 WINED3DRS_STENCILMASK ,
8110 WINED3DRS_STENCILPASS ,
8111 WINED3DRS_STENCILREF ,
8112 WINED3DRS_STENCILWRITEMASK ,
8113 WINED3DRS_STENCILZFAIL ,
8114 WINED3DRS_TEXTUREFACTOR ,
8125 WINED3DRS_ZWRITEENABLE
8128 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
8129 WINED3DTSS_ALPHAARG0 ,
8130 WINED3DTSS_ALPHAARG1 ,
8131 WINED3DTSS_ALPHAARG2 ,
8132 WINED3DTSS_ALPHAOP ,
8133 WINED3DTSS_BUMPENVLOFFSET ,
8134 WINED3DTSS_BUMPENVLSCALE ,
8135 WINED3DTSS_BUMPENVMAT00 ,
8136 WINED3DTSS_BUMPENVMAT01 ,
8137 WINED3DTSS_BUMPENVMAT10 ,
8138 WINED3DTSS_BUMPENVMAT11 ,
8139 WINED3DTSS_COLORARG0 ,
8140 WINED3DTSS_COLORARG1 ,
8141 WINED3DTSS_COLORARG2 ,
8142 WINED3DTSS_COLOROP ,
8143 WINED3DTSS_RESULTARG ,
8144 WINED3DTSS_TEXCOORDINDEX ,
8145 WINED3DTSS_TEXTURETRANSFORMFLAGS
8148 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
8149 WINED3DSAMP_ADDRESSU ,
8150 WINED3DSAMP_ADDRESSV ,
8151 WINED3DSAMP_ADDRESSW ,
8152 WINED3DSAMP_BORDERCOLOR ,
8153 WINED3DSAMP_MAGFILTER ,
8154 WINED3DSAMP_MINFILTER ,
8155 WINED3DSAMP_MIPFILTER ,
8156 WINED3DSAMP_MIPMAPLODBIAS ,
8157 WINED3DSAMP_MAXMIPLEVEL ,
8158 WINED3DSAMP_MAXANISOTROPY ,
8159 WINED3DSAMP_SRGBTEXTURE ,
8160 WINED3DSAMP_ELEMENTINDEX
8163 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
8165 WINED3DRS_AMBIENTMATERIALSOURCE ,
8166 WINED3DRS_CLIPPING ,
8167 WINED3DRS_CLIPPLANEENABLE ,
8168 WINED3DRS_COLORVERTEX ,
8169 WINED3DRS_DIFFUSEMATERIALSOURCE ,
8170 WINED3DRS_EMISSIVEMATERIALSOURCE ,
8171 WINED3DRS_FOGDENSITY ,
8173 WINED3DRS_FOGSTART ,
8174 WINED3DRS_FOGTABLEMODE ,
8175 WINED3DRS_FOGVERTEXMODE ,
8176 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
8177 WINED3DRS_LIGHTING ,
8178 WINED3DRS_LOCALVIEWER ,
8179 WINED3DRS_MULTISAMPLEANTIALIAS ,
8180 WINED3DRS_MULTISAMPLEMASK ,
8181 WINED3DRS_NORMALIZENORMALS ,
8182 WINED3DRS_PATCHEDGESTYLE ,
8183 WINED3DRS_POINTSCALE_A ,
8184 WINED3DRS_POINTSCALE_B ,
8185 WINED3DRS_POINTSCALE_C ,
8186 WINED3DRS_POINTSCALEENABLE ,
8187 WINED3DRS_POINTSIZE ,
8188 WINED3DRS_POINTSIZE_MAX ,
8189 WINED3DRS_POINTSIZE_MIN ,
8190 WINED3DRS_POINTSPRITEENABLE ,
8191 WINED3DRS_RANGEFOGENABLE ,
8192 WINED3DRS_SPECULARMATERIALSOURCE ,
8193 WINED3DRS_TWEENFACTOR ,
8194 WINED3DRS_VERTEXBLEND ,
8195 WINED3DRS_CULLMODE ,
8199 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8200 WINED3DTSS_TEXCOORDINDEX ,
8201 WINED3DTSS_TEXTURETRANSFORMFLAGS
8204 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8205 WINED3DSAMP_DMAPOFFSET
8208 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
8209 DWORD rep = This->StateTable[state].representative;
8213 WineD3DContext *context;
8216 for(i = 0; i < This->numContexts; i++) {
8217 context = This->contexts[i];
8218 if(isStateDirty(context, rep)) continue;
8220 context->dirtyArray[context->numDirtyEntries++] = rep;
8223 context->isStateDirty[idx] |= (1 << shift);
8227 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8228 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8229 /* The drawable size of a pbuffer render target is the current pbuffer size
8231 *width = dev->pbufferWidth;
8232 *height = dev->pbufferHeight;
8235 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8236 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
8238 *width = This->pow2Width;
8239 *height = This->pow2Height;
8242 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8243 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8244 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
8245 * current context's drawable, which is the size of the back buffer of the swapchain
8246 * the active context belongs to. The back buffer of the swapchain is stored as the
8247 * surface the context belongs to.
8249 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
8250 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;