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.0f, 1.0f, 1.0f, 0.0f }, /* Diffuse r,g,b,a */
43 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Specular r,g,b,a */
44 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Ambient r,g,b,a, */
45 { 0.0f, 0.0f, 0.0f }, /* Position x,y,z */
46 { 0.0f, 0.0f, 1.0f }, /* Direction x,y,z */
49 0.0f, 0.0f, 0.0f, /* Attenuation 0,1,2 */
54 /**********************************************************
55 * Global variable / Constants follow
56 **********************************************************/
57 const float identity[] =
59 1.0f, 0.0f, 0.0f, 0.0f,
60 0.0f, 1.0f, 0.0f, 0.0f,
61 0.0f, 0.0f, 1.0f, 0.0f,
62 0.0f, 0.0f, 0.0f, 1.0f,
63 }; /* When needed for comparisons */
65 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
66 * actually have the same values in GL and D3D. */
67 static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
69 switch(primitive_type)
71 case WINED3DPT_POINTLIST:
74 case WINED3DPT_LINELIST:
77 case WINED3DPT_LINESTRIP:
80 case WINED3DPT_TRIANGLELIST:
83 case WINED3DPT_TRIANGLESTRIP:
84 return GL_TRIANGLE_STRIP;
86 case WINED3DPT_TRIANGLEFAN:
87 return GL_TRIANGLE_FAN;
89 case WINED3DPT_LINELIST_ADJ:
90 return GL_LINES_ADJACENCY_ARB;
92 case WINED3DPT_LINESTRIP_ADJ:
93 return GL_LINE_STRIP_ADJACENCY_ARB;
95 case WINED3DPT_TRIANGLELIST_ADJ:
96 return GL_TRIANGLES_ADJACENCY_ARB;
98 case WINED3DPT_TRIANGLESTRIP_ADJ:
99 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
102 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
107 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
109 switch(primitive_type)
112 return WINED3DPT_POINTLIST;
115 return WINED3DPT_LINELIST;
118 return WINED3DPT_LINESTRIP;
121 return WINED3DPT_TRIANGLELIST;
123 case GL_TRIANGLE_STRIP:
124 return WINED3DPT_TRIANGLESTRIP;
126 case GL_TRIANGLE_FAN:
127 return WINED3DPT_TRIANGLEFAN;
129 case GL_LINES_ADJACENCY_ARB:
130 return WINED3DPT_LINELIST_ADJ;
132 case GL_LINE_STRIP_ADJACENCY_ARB:
133 return WINED3DPT_LINESTRIP_ADJ;
135 case GL_TRIANGLES_ADJACENCY_ARB:
136 return WINED3DPT_TRIANGLELIST_ADJ;
138 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
139 return WINED3DPT_TRIANGLESTRIP_ADJ;
142 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
143 return WINED3DPT_UNDEFINED;
147 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
149 if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && usage_idx == 0)
150 *regnum = WINED3D_FFP_POSITION;
151 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
152 *regnum = WINED3D_FFP_BLENDWEIGHT;
153 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
154 *regnum = WINED3D_FFP_BLENDINDICES;
155 else if (usage == WINED3DDECLUSAGE_NORMAL && usage_idx == 0)
156 *regnum = WINED3D_FFP_NORMAL;
157 else if (usage == WINED3DDECLUSAGE_PSIZE && usage_idx == 0)
158 *regnum = WINED3D_FFP_PSIZE;
159 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 0)
160 *regnum = WINED3D_FFP_DIFFUSE;
161 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1)
162 *regnum = WINED3D_FFP_SPECULAR;
163 else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
164 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
167 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
175 /* Context activation is done by the caller. */
176 void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
177 BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
179 /* We need to deal with frequency data! */
180 IWineD3DVertexDeclarationImpl *declaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
181 UINT stream_count = This->stateBlock->streamIsUP ? 0 : declaration->num_streams;
182 const DWORD *streams = declaration->streams;
185 memset(stream_info, 0, sizeof(*stream_info));
187 /* Check for transformed vertices, disable vertex shader if present. */
188 stream_info->position_transformed = declaration->position_transformed;
189 if (declaration->position_transformed) use_vshader = FALSE;
191 /* Translate the declaration into strided data. */
192 for (i = 0; i < declaration->element_count; ++i)
194 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
195 GLuint buffer_object = 0;
196 const BYTE *data = NULL;
201 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
202 element, i + 1, declaration->element_count);
204 if (!This->stateBlock->streamSource[element->input_slot]) continue;
206 stride = This->stateBlock->streamStride[element->input_slot];
207 if (This->stateBlock->streamIsUP)
209 TRACE("Stream %u is UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
211 data = (BYTE *)This->stateBlock->streamSource[element->input_slot];
215 TRACE("Stream %u isn't UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
216 data = buffer_get_memory(This->stateBlock->streamSource[element->input_slot], 0, &buffer_object);
218 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
219 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
220 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
221 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
222 * not, drawStridedSlow is needed, including a vertex buffer path. */
223 if (This->stateBlock->loadBaseVertexIndex < 0)
225 WARN("loadBaseVertexIndex is < 0 (%d), not using vbos\n", This->stateBlock->loadBaseVertexIndex);
227 data = buffer_get_sysmem((struct wined3d_buffer *)This->stateBlock->streamSource[element->input_slot]);
228 if ((UINT_PTR)data < -This->stateBlock->loadBaseVertexIndex * stride)
230 FIXME("System memory vertex data load offset is negative!\n");
236 if (buffer_object) *fixup = TRUE;
237 else if (*fixup && !use_vshader
238 && (element->usage == WINED3DDECLUSAGE_COLOR
239 || element->usage == WINED3DDECLUSAGE_POSITIONT))
241 static BOOL warned = FALSE;
244 /* This may be bad with the fixed function pipeline. */
245 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
251 data += element->offset;
253 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
257 if (element->output_slot == ~0U)
259 /* TODO: Assuming vertexdeclarations are usually used with the
260 * same or a similar shader, it might be worth it to store the
261 * last used output slot and try that one first. */
262 stride_used = vshader_get_input(This->stateBlock->vertexShader,
263 element->usage, element->usage_idx, &idx);
267 idx = element->output_slot;
273 if (!element->ffp_valid)
275 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
276 debug_d3dformat(element->format_desc->format), debug_d3ddeclusage(element->usage));
281 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
287 TRACE("Load %s array %u [usage %s, usage_idx %u, "
288 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
289 use_vshader ? "shader": "fixed function", idx,
290 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
291 element->offset, stride, debug_d3dformat(element->format_desc->format), buffer_object);
293 stream_info->elements[idx].format_desc = element->format_desc;
294 stream_info->elements[idx].stride = stride;
295 stream_info->elements[idx].data = data;
296 stream_info->elements[idx].stream_idx = element->input_slot;
297 stream_info->elements[idx].buffer_object = buffer_object;
299 if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA) && element->format_desc->format == WINED3DFMT_A8R8G8B8)
301 stream_info->swizzle_map |= 1 << idx;
303 stream_info->use_map |= 1 << idx;
307 /* Now call PreLoad on all the vertex buffers. In the very rare case
308 * that the buffers stopps converting PreLoad will dirtify the VDECL again.
309 * The vertex buffer can now use the strided structure in the device instead of finding its
312 * NULL streams won't be recorded in the array, UP streams won't be either. A stream is only
314 for (i = 0; i < stream_count; ++i)
316 IWineD3DBuffer *vb = This->stateBlock->streamSource[streams[i]];
317 if (vb) IWineD3DBuffer_PreLoad(vb);
321 static void stream_info_element_from_strided(IWineD3DDeviceImpl *This,
322 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
324 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(strided->format, &This->adapter->gl_info);
325 e->format_desc = format_desc;
326 e->stride = strided->dwStride;
327 e->data = strided->lpData;
329 e->buffer_object = 0;
332 void device_stream_info_from_strided(IWineD3DDeviceImpl *This,
333 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
337 memset(stream_info, 0, sizeof(*stream_info));
339 if (strided->position.lpData)
340 stream_info_element_from_strided(This, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
341 if (strided->normal.lpData)
342 stream_info_element_from_strided(This, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
343 if (strided->diffuse.lpData)
344 stream_info_element_from_strided(This, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
345 if (strided->specular.lpData)
346 stream_info_element_from_strided(This, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
348 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
350 if (strided->texCoords[i].lpData)
351 stream_info_element_from_strided(This, &strided->texCoords[i],
352 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
355 stream_info->position_transformed = strided->position_transformed;
357 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
359 if (!stream_info->elements[i].format_desc) continue;
361 if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA) && stream_info->elements[i].format_desc->format == WINED3DFMT_A8R8G8B8)
363 stream_info->swizzle_map |= 1 << i;
365 stream_info->use_map |= 1 << i;
369 /**********************************************************
370 * IUnknown parts follows
371 **********************************************************/
373 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
375 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
377 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
378 if (IsEqualGUID(riid, &IID_IUnknown)
379 || IsEqualGUID(riid, &IID_IWineD3DBase)
380 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
381 IUnknown_AddRef(iface);
386 return E_NOINTERFACE;
389 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
391 ULONG refCount = InterlockedIncrement(&This->ref);
393 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
397 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
398 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
399 ULONG refCount = InterlockedDecrement(&This->ref);
401 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
406 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
407 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
408 This->multistate_funcs[i] = NULL;
411 /* TODO: Clean up all the surfaces and textures! */
412 /* NOTE: You must release the parent if the object was created via a callback
413 ** ***************************/
415 if (!list_empty(&This->resources)) {
416 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
417 dumpResources(&This->resources);
420 if(This->contexts) ERR("Context array not freed!\n");
421 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
422 This->haveHardwareCursor = FALSE;
424 IWineD3D_Release(This->wineD3D);
425 This->wineD3D = NULL;
426 HeapFree(GetProcessHeap(), 0, This);
427 TRACE("Freed device %p\n", This);
433 /**********************************************************
434 * IWineD3DDevice implementation follows
435 **********************************************************/
436 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
437 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
438 *pParent = This->parent;
439 IUnknown_AddRef(This->parent);
443 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface,
444 struct wined3d_buffer_desc *desc, const void *data, IUnknown *parent, IWineD3DBuffer **buffer)
446 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
447 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(WINED3DFMT_UNKNOWN, &This->adapter->gl_info);
448 struct wined3d_buffer *object;
451 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
453 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
456 ERR("Failed to allocate memory\n");
457 return E_OUTOFMEMORY;
460 object->vtbl = &wined3d_buffer_vtbl;
461 object->desc = *desc;
463 FIXME("Ignoring access flags (pool)\n");
465 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_BUFFER, This, desc->byte_width,
466 desc->usage, format_desc, WINED3DPOOL_MANAGED, parent);
469 WARN("Failed to initialize resource, returning %#x\n", hr);
470 HeapFree(GetProcessHeap(), 0, object);
473 object->buffer_type_hint = GL_ARRAY_BUFFER_ARB;
475 TRACE("Created resource %p\n", object);
477 TRACE("size %#x, usage=%#x, format %s, memory @ %p, iface @ %p\n", object->resource.size, object->resource.usage,
478 debug_d3dformat(object->resource.format_desc->format), object->resource.allocatedMemory, object);
484 hr = IWineD3DBuffer_Map((IWineD3DBuffer *)object, 0, desc->byte_width, &ptr, 0);
487 ERR("Failed to map buffer, hr %#x\n", hr);
488 IWineD3DBuffer_Release((IWineD3DBuffer *)object);
492 memcpy(ptr, data, desc->byte_width);
494 hr = IWineD3DBuffer_Unmap((IWineD3DBuffer *)object);
497 ERR("Failed to unmap buffer, hr %#x\n", hr);
498 IWineD3DBuffer_Release((IWineD3DBuffer *)object);
503 *buffer = (IWineD3DBuffer *)object;
508 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
509 DWORD FVF, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer, IUnknown *parent)
511 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
512 /* Dummy format for now */
513 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(WINED3DFMT_VERTEXDATA, &This->adapter->gl_info);
514 struct wined3d_buffer *object;
515 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
520 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
521 *ppVertexBuffer = NULL;
522 return WINED3DERR_INVALIDCALL;
523 } else if(Pool == WINED3DPOOL_SCRATCH) {
524 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
525 * anyway, SCRATCH vertex buffers aren't usable anywhere
527 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
528 *ppVertexBuffer = NULL;
529 return WINED3DERR_INVALIDCALL;
532 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
535 ERR("Out of memory\n");
536 *ppVertexBuffer = NULL;
537 return WINED3DERR_OUTOFVIDEOMEMORY;
540 object->vtbl = &wined3d_buffer_vtbl;
541 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_BUFFER, This, Size, Usage, format_desc, Pool, parent);
544 WARN("Failed to initialize resource, returning %#x\n", hr);
545 HeapFree(GetProcessHeap(), 0, object);
546 *ppVertexBuffer = NULL;
549 object->buffer_type_hint = GL_ARRAY_BUFFER_ARB;
551 TRACE("(%p) : Created resource %p\n", This, object);
553 TRACE("(%p) : Size=%d, Usage=0x%08x, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
554 *ppVertexBuffer = (IWineD3DBuffer *)object;
556 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
557 * drawStridedFast (half-life 2).
559 * Basically converting the vertices in the buffer is quite expensive, and observations
560 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
561 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
563 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
564 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
565 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
566 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
568 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
569 * more. In this call we can convert dx7 buffers too.
571 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
572 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
573 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
574 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
575 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
576 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
577 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
578 } else if(dxVersion <= 7 && conv) {
579 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
581 object->flags |= WINED3D_BUFFER_CREATEBO;
586 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
587 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer, IUnknown *parent)
589 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
590 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(WINED3DFMT_UNKNOWN, &This->adapter->gl_info);
591 struct wined3d_buffer *object;
594 TRACE("(%p) Creating index buffer\n", This);
596 /* Allocate the storage for the device */
597 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
600 ERR("Out of memory\n");
601 *ppIndexBuffer = NULL;
602 return WINED3DERR_OUTOFVIDEOMEMORY;
605 object->vtbl = &wined3d_buffer_vtbl;
606 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_BUFFER, This, Length, Usage, format_desc, Pool, parent);
609 WARN("Failed to initialize resource, returning %#x\n", hr);
610 HeapFree(GetProcessHeap(), 0, object);
611 *ppIndexBuffer = NULL;
614 object->buffer_type_hint = GL_ELEMENT_ARRAY_BUFFER_ARB;
616 TRACE("(%p) : Created resource %p\n", This, object);
618 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
619 object->flags |= WINED3D_BUFFER_CREATEBO;
622 TRACE("(%p) : Len=%d, Use=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage,
623 Pool, object, object->resource.allocatedMemory);
624 *ppIndexBuffer = (IWineD3DBuffer *) object;
629 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
632 IWineD3DStateBlockImpl *object;
636 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
639 ERR("Out of memory\n");
640 *ppStateBlock = NULL;
641 return WINED3DERR_OUTOFVIDEOMEMORY;
644 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
645 object->wineD3DDevice = This;
646 object->parent = parent;
648 object->blockType = Type;
650 *ppStateBlock = (IWineD3DStateBlock *)object;
652 for(i = 0; i < LIGHTMAP_SIZE; i++) {
653 list_init(&object->lightMap[i]);
656 temp_result = allocate_shader_constants(object);
657 if (FAILED(temp_result))
659 HeapFree(GetProcessHeap(), 0, object);
663 /* Special case - Used during initialization to produce a placeholder stateblock
664 so other functions called can update a state block */
665 if (Type == WINED3DSBT_INIT || Type == WINED3DSBT_RECORDED)
667 /* Don't bother increasing the reference count otherwise a device will never
668 be freed due to circular dependencies */
672 /* Otherwise, might as well set the whole state block to the appropriate values */
673 if (This->stateBlock != NULL)
674 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
676 memset(object->streamFreq, 1, sizeof(object->streamFreq));
678 /* Reset the ref and type after kludging it */
679 object->wineD3DDevice = This;
681 object->blockType = Type;
683 TRACE("Updating changed flags appropriate for type %d\n", Type);
685 if (Type == WINED3DSBT_ALL) {
687 TRACE("ALL => Pretend everything has changed\n");
688 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
690 /* Lights are not part of the changed / set structure */
691 for(j = 0; j < LIGHTMAP_SIZE; j++) {
693 LIST_FOR_EACH(e, &object->lightMap[j]) {
694 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
695 light->changed = TRUE;
696 light->enabledChanged = TRUE;
699 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
700 object->contained_render_states[j - 1] = j;
702 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
703 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
704 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
705 object->contained_transform_states[j - 1] = j;
707 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
708 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
709 object->contained_vs_consts_f[j] = j;
711 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
712 for(j = 0; j < MAX_CONST_I; j++) {
713 object->contained_vs_consts_i[j] = j;
715 object->num_contained_vs_consts_i = MAX_CONST_I;
716 for(j = 0; j < MAX_CONST_B; j++) {
717 object->contained_vs_consts_b[j] = j;
719 object->num_contained_vs_consts_b = MAX_CONST_B;
720 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
721 object->contained_ps_consts_f[j] = j;
723 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
724 for(j = 0; j < MAX_CONST_I; j++) {
725 object->contained_ps_consts_i[j] = j;
727 object->num_contained_ps_consts_i = MAX_CONST_I;
728 for(j = 0; j < MAX_CONST_B; j++) {
729 object->contained_ps_consts_b[j] = j;
731 object->num_contained_ps_consts_b = MAX_CONST_B;
732 for(i = 0; i < MAX_TEXTURES; i++) {
733 for (j = 0; j <= WINED3D_HIGHEST_TEXTURE_STATE; ++j)
735 object->contained_tss_states[object->num_contained_tss_states].stage = i;
736 object->contained_tss_states[object->num_contained_tss_states].state = j;
737 object->num_contained_tss_states++;
740 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
741 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
742 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
743 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
744 object->num_contained_sampler_states++;
748 for(i = 0; i < MAX_STREAMS; i++) {
749 if(object->streamSource[i]) {
750 IWineD3DBuffer_AddRef(object->streamSource[i]);
753 if(object->pIndexData) {
754 IWineD3DBuffer_AddRef(object->pIndexData);
756 if(object->vertexShader) {
757 IWineD3DVertexShader_AddRef(object->vertexShader);
759 if(object->pixelShader) {
760 IWineD3DPixelShader_AddRef(object->pixelShader);
763 } else if (Type == WINED3DSBT_PIXELSTATE) {
765 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
766 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
768 object->changed.pixelShader = TRUE;
770 /* Pixel Shader Constants */
771 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
772 object->contained_ps_consts_f[i] = i;
773 object->changed.pixelShaderConstantsF[i] = TRUE;
775 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
776 for (i = 0; i < MAX_CONST_B; ++i) {
777 object->contained_ps_consts_b[i] = i;
778 object->changed.pixelShaderConstantsB |= (1 << i);
780 object->num_contained_ps_consts_b = MAX_CONST_B;
781 for (i = 0; i < MAX_CONST_I; ++i) {
782 object->contained_ps_consts_i[i] = i;
783 object->changed.pixelShaderConstantsI |= (1 << i);
785 object->num_contained_ps_consts_i = MAX_CONST_I;
787 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
788 DWORD rs = SavedPixelStates_R[i];
789 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
790 object->contained_render_states[i] = rs;
792 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
793 for (j = 0; j < MAX_TEXTURES; j++) {
794 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
795 DWORD state = SavedPixelStates_T[i];
796 object->changed.textureState[j] |= 1 << state;
797 object->contained_tss_states[object->num_contained_tss_states].stage = j;
798 object->contained_tss_states[object->num_contained_tss_states].state = state;
799 object->num_contained_tss_states++;
802 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
803 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
804 DWORD state = SavedPixelStates_S[i];
805 object->changed.samplerState[j] |= 1 << state;
806 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
807 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
808 object->num_contained_sampler_states++;
811 if(object->pixelShader) {
812 IWineD3DPixelShader_AddRef(object->pixelShader);
815 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
816 * on them. This makes releasing the buffer easier
818 for(i = 0; i < MAX_STREAMS; i++) {
819 object->streamSource[i] = NULL;
821 object->pIndexData = NULL;
822 object->vertexShader = NULL;
824 } else if (Type == WINED3DSBT_VERTEXSTATE) {
826 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
827 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
829 object->changed.vertexShader = TRUE;
831 /* Vertex Shader Constants */
832 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
833 object->changed.vertexShaderConstantsF[i] = TRUE;
834 object->contained_vs_consts_f[i] = i;
836 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
837 for (i = 0; i < MAX_CONST_B; ++i) {
838 object->contained_vs_consts_b[i] = i;
839 object->changed.vertexShaderConstantsB |= (1 << i);
841 object->num_contained_vs_consts_b = MAX_CONST_B;
842 for (i = 0; i < MAX_CONST_I; ++i) {
843 object->contained_vs_consts_i[i] = i;
844 object->changed.vertexShaderConstantsI |= (1 << i);
846 object->num_contained_vs_consts_i = MAX_CONST_I;
847 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
848 DWORD rs = SavedVertexStates_R[i];
849 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
850 object->contained_render_states[i] = rs;
852 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
853 for (j = 0; j < MAX_TEXTURES; j++) {
854 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
855 DWORD state = SavedVertexStates_T[i];
856 object->changed.textureState[j] |= 1 << state;
857 object->contained_tss_states[object->num_contained_tss_states].stage = j;
858 object->contained_tss_states[object->num_contained_tss_states].state = state;
859 object->num_contained_tss_states++;
862 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
863 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
864 DWORD state = SavedVertexStates_S[i];
865 object->changed.samplerState[j] |= 1 << state;
866 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
867 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
868 object->num_contained_sampler_states++;
872 for(j = 0; j < LIGHTMAP_SIZE; j++) {
874 LIST_FOR_EACH(e, &object->lightMap[j]) {
875 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
876 light->changed = TRUE;
877 light->enabledChanged = TRUE;
881 for(i = 0; i < MAX_STREAMS; i++) {
882 if(object->streamSource[i]) {
883 IWineD3DBuffer_AddRef(object->streamSource[i]);
886 if(object->vertexShader) {
887 IWineD3DVertexShader_AddRef(object->vertexShader);
889 object->pIndexData = NULL;
890 object->pixelShader = NULL;
892 FIXME("Unrecognized state block type %d\n", Type);
895 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
899 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
900 WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,
901 DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
902 WINED3DSURFTYPE Impl, IUnknown *parent)
904 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
905 IWineD3DSurfaceImpl *object;
908 TRACE("(%p) Create surface\n",This);
910 if (Impl == SURFACE_OPENGL && !This->adapter)
912 ERR("OpenGL surfaces are not available without OpenGL.\n");
913 return WINED3DERR_NOTAVAILABLE;
916 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
919 ERR("Failed to allocate surface memory.\n");
921 return WINED3DERR_OUTOFVIDEOMEMORY;
924 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
925 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent);
928 WARN("Failed to initialize surface, returning %#x.\n", hr);
929 HeapFree(GetProcessHeap(), 0, object);
934 TRACE("(%p) : Created surface %p\n", This, object);
936 *ppSurface = (IWineD3DSurface *)object;
941 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
942 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
944 struct wined3d_rendertarget_view *object;
946 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
949 ERR("Failed to allocate memory\n");
950 return E_OUTOFMEMORY;
953 object->vtbl = &wined3d_rendertarget_view_vtbl;
954 object->refcount = 1;
955 IWineD3DResource_AddRef(resource);
956 object->resource = resource;
957 object->parent = parent;
959 *rendertarget_view = (IWineD3DRendertargetView *)object;
964 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
965 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
966 WINED3DPOOL Pool, IWineD3DTexture **ppTexture, IUnknown *parent)
968 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
969 IWineD3DTextureImpl *object;
972 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
973 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
974 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
976 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
979 ERR("Out of memory\n");
981 return WINED3DERR_OUTOFVIDEOMEMORY;
984 object->lpVtbl = &IWineD3DTexture_Vtbl;
986 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent);
989 WARN("Failed to initialize texture, returning %#x\n", hr);
990 HeapFree(GetProcessHeap(), 0, object);
995 *ppTexture = (IWineD3DTexture *)object;
997 TRACE("(%p) : Created texture %p\n", This, object);
1002 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1003 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
1004 WINED3DPOOL Pool, IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent)
1006 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1007 IWineD3DVolumeTextureImpl *object;
1010 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1011 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1013 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1016 ERR("Out of memory\n");
1017 *ppVolumeTexture = NULL;
1018 return WINED3DERR_OUTOFVIDEOMEMORY;
1021 object->lpVtbl = &IWineD3DVolumeTexture_Vtbl;
1022 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent);
1025 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
1026 HeapFree(GetProcessHeap(), 0, object);
1027 *ppVolumeTexture = NULL;
1031 TRACE("(%p) : Created volume texture %p.\n", This, object);
1032 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
1037 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1038 UINT Width, UINT Height, UINT Depth, DWORD Usage, WINED3DFORMAT Format,
1039 WINED3DPOOL Pool, IWineD3DVolume **ppVolume, IUnknown *parent)
1041 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1042 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1043 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(Format, &GLINFO_LOCATION);
1046 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1047 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1048 return WINED3DERR_INVALIDCALL;
1051 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1054 ERR("Out of memory\n");
1056 return WINED3DERR_OUTOFVIDEOMEMORY;
1059 object->lpVtbl = &IWineD3DVolume_Vtbl;
1060 hr = resource_init((IWineD3DResource *)object, WINED3DRTYPE_VOLUME, This,
1061 Width * Height * Depth * format_desc->byte_count, Usage, format_desc, Pool, parent);
1064 WARN("Failed to initialize resource, returning %#x\n", hr);
1065 HeapFree(GetProcessHeap(), 0, object);
1070 TRACE("(%p) : Created resource %p\n", This, object);
1072 *ppVolume = (IWineD3DVolume *)object;
1074 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1075 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1077 object->currentDesc.Width = Width;
1078 object->currentDesc.Height = Height;
1079 object->currentDesc.Depth = Depth;
1081 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1082 object->lockable = TRUE;
1083 object->locked = FALSE;
1084 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1085 object->dirty = TRUE;
1087 volume_add_dirty_box((IWineD3DVolume *)object, NULL);
1092 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface,
1093 UINT EdgeLength, UINT Levels, DWORD Usage, WINED3DFORMAT Format,
1094 WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture, IUnknown *parent)
1096 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1097 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1100 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1103 ERR("Out of memory\n");
1104 *ppCubeTexture = NULL;
1105 return WINED3DERR_OUTOFVIDEOMEMORY;
1108 object->lpVtbl = &IWineD3DCubeTexture_Vtbl;
1109 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent);
1112 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1113 HeapFree(GetProcessHeap(), 0, object);
1114 *ppCubeTexture = NULL;
1118 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1119 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1124 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1125 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1126 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1127 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1128 const IWineD3DQueryVtbl *vtable;
1130 /* Just a check to see if we support this type of query */
1132 case WINED3DQUERYTYPE_OCCLUSION:
1133 TRACE("(%p) occlusion query\n", This);
1134 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1137 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1139 vtable = &IWineD3DOcclusionQuery_Vtbl;
1142 case WINED3DQUERYTYPE_EVENT:
1143 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1144 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1145 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1147 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1149 vtable = &IWineD3DEventQuery_Vtbl;
1153 case WINED3DQUERYTYPE_VCACHE:
1154 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1155 case WINED3DQUERYTYPE_VERTEXSTATS:
1156 case WINED3DQUERYTYPE_TIMESTAMP:
1157 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1158 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1159 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1160 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1161 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1162 case WINED3DQUERYTYPE_PIXELTIMINGS:
1163 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1164 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1166 /* Use the base Query vtable until we have a special one for each query */
1167 vtable = &IWineD3DQuery_Vtbl;
1168 FIXME("(%p) Unhandled query type %d\n", This, Type);
1170 if(NULL == ppQuery || hr != WINED3D_OK) {
1174 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1177 ERR("Out of memory\n");
1179 return WINED3DERR_OUTOFVIDEOMEMORY;
1182 object->lpVtbl = vtable;
1183 object->type = Type;
1184 object->state = QUERY_CREATED;
1185 object->wineD3DDevice = This;
1186 object->parent = parent;
1189 *ppQuery = (IWineD3DQuery *)object;
1191 /* allocated the 'extended' data based on the type of query requested */
1193 case WINED3DQUERYTYPE_OCCLUSION:
1194 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1195 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1197 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1198 TRACE("(%p) Allocating data for an occlusion query\n", This);
1200 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
1202 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1206 case WINED3DQUERYTYPE_EVENT:
1207 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1208 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1210 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
1212 if(GL_SUPPORT(APPLE_FENCE)) {
1213 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1214 checkGLcall("glGenFencesAPPLE");
1215 } else if(GL_SUPPORT(NV_FENCE)) {
1216 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1217 checkGLcall("glGenFencesNV");
1222 case WINED3DQUERYTYPE_VCACHE:
1223 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1224 case WINED3DQUERYTYPE_VERTEXSTATS:
1225 case WINED3DQUERYTYPE_TIMESTAMP:
1226 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1227 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1228 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1229 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1230 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1231 case WINED3DQUERYTYPE_PIXELTIMINGS:
1232 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1233 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1235 object->extendedData = 0;
1236 FIXME("(%p) Unhandled query type %d\n",This , Type);
1238 TRACE("(%p) : Created Query %p\n", This, object);
1242 /*****************************************************************************
1243 * IWineD3DDeviceImpl_SetupFullscreenWindow
1245 * Helper function that modifies a HWND's Style and ExStyle for proper
1249 * iface: Pointer to the IWineD3DDevice interface
1250 * window: Window to setup
1252 *****************************************************************************/
1253 static LONG fullscreen_style(LONG orig_style) {
1254 LONG style = orig_style;
1255 style &= ~WS_CAPTION;
1256 style &= ~WS_THICKFRAME;
1258 /* Make sure the window is managed, otherwise we won't get keyboard input */
1259 style |= WS_POPUP | WS_SYSMENU;
1264 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1265 LONG exStyle = orig_exStyle;
1267 /* Filter out window decorations */
1268 exStyle &= ~WS_EX_WINDOWEDGE;
1269 exStyle &= ~WS_EX_CLIENTEDGE;
1274 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1275 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1277 LONG style, exStyle;
1278 /* Don't do anything if an original style is stored.
1279 * That shouldn't happen
1281 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1282 if (This->style || This->exStyle) {
1283 ERR("(%p): Want to change the window parameters of HWND %p, but "
1284 "another style is stored for restoration afterwards\n", This, window);
1287 /* Get the parameters and save them */
1288 style = GetWindowLongW(window, GWL_STYLE);
1289 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1290 This->style = style;
1291 This->exStyle = exStyle;
1293 style = fullscreen_style(style);
1294 exStyle = fullscreen_exStyle(exStyle);
1296 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1297 This->style, This->exStyle, style, exStyle);
1299 SetWindowLongW(window, GWL_STYLE, style);
1300 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1302 /* Inform the window about the update. */
1303 SetWindowPos(window, HWND_TOP, 0, 0,
1304 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1307 /*****************************************************************************
1308 * IWineD3DDeviceImpl_RestoreWindow
1310 * Helper function that restores a windows' properties when taking it out
1311 * of fullscreen mode
1314 * iface: Pointer to the IWineD3DDevice interface
1315 * window: Window to setup
1317 *****************************************************************************/
1318 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1319 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1320 LONG style, exStyle;
1322 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1323 * switch, do nothing
1325 if (!This->style && !This->exStyle) return;
1327 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1328 This, window, This->style, This->exStyle);
1330 style = GetWindowLongW(window, GWL_STYLE);
1331 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1333 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1334 * Some applications change it before calling Reset() when switching between windowed and
1335 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1337 if(style == fullscreen_style(This->style) &&
1338 exStyle == fullscreen_style(This->exStyle)) {
1339 SetWindowLongW(window, GWL_STYLE, This->style);
1340 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1343 /* Delete the old values */
1347 /* Inform the window about the update */
1348 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1349 0, 0, 0, 0, /* Pos, Size, ignored */
1350 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1353 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1354 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1355 WINED3DPRESENT_PARAMETERS *pPresentationParameters, IWineD3DSwapChain **ppSwapChain,
1356 IUnknown *parent, WINED3DSURFTYPE surface_type)
1358 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1361 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1363 IUnknown *bufferParent;
1364 BOOL displaymode_set = FALSE;
1365 WINED3DDISPLAYMODE Mode;
1366 const struct GlPixelFormatDesc *format_desc;
1368 TRACE("(%p) : Created Additional Swap Chain\n", This);
1370 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1371 * does a device hold a reference to a swap chain giving them a lifetime of the device
1372 * or does the swap chain notify the device of its destruction.
1373 *******************************/
1375 /* Check the params */
1376 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1377 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1378 return WINED3DERR_INVALIDCALL;
1379 } else if (pPresentationParameters->BackBufferCount > 1) {
1380 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");
1383 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1386 ERR("Out of memory\n");
1387 *ppSwapChain = NULL;
1388 return WINED3DERR_OUTOFVIDEOMEMORY;
1391 switch(surface_type) {
1393 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1395 case SURFACE_OPENGL:
1396 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1398 case SURFACE_UNKNOWN:
1399 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1400 HeapFree(GetProcessHeap(), 0, object);
1401 return WINED3DERR_INVALIDCALL;
1403 object->wineD3DDevice = This;
1404 object->parent = parent;
1407 *ppSwapChain = (IWineD3DSwapChain *)object;
1409 /*********************
1410 * Lookup the window Handle and the relating X window handle
1411 ********************/
1413 /* Setup hwnd we are using, plus which display this equates to */
1414 object->win_handle = pPresentationParameters->hDeviceWindow;
1415 if (!object->win_handle) {
1416 object->win_handle = This->createParms.hFocusWindow;
1418 if(!pPresentationParameters->Windowed && object->win_handle) {
1419 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1420 pPresentationParameters->BackBufferWidth,
1421 pPresentationParameters->BackBufferHeight);
1424 hDc = GetDC(object->win_handle);
1425 TRACE("Using hDc %p\n", hDc);
1428 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1429 return WINED3DERR_NOTAVAILABLE;
1432 /* Get info on the current display setup */
1433 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1434 object->orig_width = Mode.Width;
1435 object->orig_height = Mode.Height;
1436 object->orig_fmt = Mode.Format;
1437 format_desc = getFormatDescEntry(Mode.Format, &GLINFO_LOCATION);
1439 if (pPresentationParameters->Windowed &&
1440 ((pPresentationParameters->BackBufferWidth == 0) ||
1441 (pPresentationParameters->BackBufferHeight == 0) ||
1442 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1445 GetClientRect(object->win_handle, &Rect);
1447 if (pPresentationParameters->BackBufferWidth == 0) {
1448 pPresentationParameters->BackBufferWidth = Rect.right;
1449 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1451 if (pPresentationParameters->BackBufferHeight == 0) {
1452 pPresentationParameters->BackBufferHeight = Rect.bottom;
1453 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1455 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1456 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1457 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1461 /* Put the correct figures in the presentation parameters */
1462 TRACE("Copying across presentation parameters\n");
1463 object->presentParms = *pPresentationParameters;
1465 TRACE("calling rendertarget CB\n");
1466 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1467 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1468 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1469 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->frontBuffer);
1470 if (SUCCEEDED(hr)) {
1471 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1472 ((IWineD3DSurfaceImpl *)object->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
1473 if(surface_type == SURFACE_OPENGL) {
1474 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1477 ERR("Failed to create the front buffer\n");
1481 /*********************
1482 * Windowed / Fullscreen
1483 *******************/
1486 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1487 * so we should really check to see if there is a fullscreen swapchain already
1488 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1489 **************************************/
1491 if (!pPresentationParameters->Windowed) {
1492 WINED3DDISPLAYMODE mode;
1495 /* Change the display settings */
1496 mode.Width = pPresentationParameters->BackBufferWidth;
1497 mode.Height = pPresentationParameters->BackBufferHeight;
1498 mode.Format = pPresentationParameters->BackBufferFormat;
1499 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1501 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1502 displaymode_set = TRUE;
1506 * Create an opengl context for the display visual
1507 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1508 * use different properties after that point in time. FIXME: How to handle when requested format
1509 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1510 * it chooses is identical to the one already being used!
1511 **********************************/
1512 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1514 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1515 if(!object->context) {
1516 ERR("Failed to create the context array\n");
1520 object->num_contexts = 1;
1522 if(surface_type == SURFACE_OPENGL) {
1523 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1524 if (!object->context[0]) {
1525 ERR("Failed to create a new context\n");
1526 hr = WINED3DERR_NOTAVAILABLE;
1529 TRACE("Context created (HWND=%p, glContext=%p)\n",
1530 object->win_handle, object->context[0]->glCtx);
1534 /*********************
1535 * Create the back, front and stencil buffers
1536 *******************/
1537 if(object->presentParms.BackBufferCount > 0) {
1540 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1541 if(!object->backBuffer) {
1542 ERR("Out of memory\n");
1547 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1548 TRACE("calling rendertarget CB\n");
1549 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1550 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1551 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1552 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->backBuffer[i]);
1554 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1555 ((IWineD3DSurfaceImpl *)object->backBuffer[i])->Flags |= SFLAG_SWAPCHAIN;
1557 ERR("Cannot create new back buffer\n");
1560 if(surface_type == SURFACE_OPENGL) {
1562 glDrawBuffer(GL_BACK);
1563 checkGLcall("glDrawBuffer(GL_BACK)");
1568 object->backBuffer = NULL;
1570 /* Single buffering - draw to front buffer */
1571 if(surface_type == SURFACE_OPENGL) {
1573 glDrawBuffer(GL_FRONT);
1574 checkGLcall("glDrawBuffer(GL_FRONT)");
1579 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1580 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1581 TRACE("Creating depth stencil buffer\n");
1582 if (This->auto_depth_stencil_buffer == NULL ) {
1583 hr = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent, parent,
1584 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1585 object->presentParms.AutoDepthStencilFormat, object->presentParms.MultiSampleType,
1586 object->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */,
1587 &This->auto_depth_stencil_buffer);
1588 if (SUCCEEDED(hr)) {
1589 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1591 ERR("Failed to create the auto depth stencil\n");
1597 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1599 TRACE("Created swapchain %p\n", object);
1600 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1604 if (displaymode_set) {
1608 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1611 /* Change the display settings */
1612 memset(&devmode, 0, sizeof(devmode));
1613 devmode.dmSize = sizeof(devmode);
1614 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1615 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1616 devmode.dmPelsWidth = object->orig_width;
1617 devmode.dmPelsHeight = object->orig_height;
1618 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1621 if (object->backBuffer) {
1623 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1624 if(object->backBuffer[i]) {
1625 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1626 IUnknown_Release(bufferParent); /* once for the get parent */
1627 if (IUnknown_Release(bufferParent) > 0) {
1628 FIXME("(%p) Something's still holding the back buffer\n",This);
1632 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1633 object->backBuffer = NULL;
1635 if(object->context && object->context[0])
1636 DestroyContext(This, object->context[0]);
1637 if(object->frontBuffer) {
1638 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1639 IUnknown_Release(bufferParent); /* once for the get parent */
1640 if (IUnknown_Release(bufferParent) > 0) {
1641 FIXME("(%p) Something's still holding the front buffer\n",This);
1644 HeapFree(GetProcessHeap(), 0, object);
1648 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1649 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1650 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1651 TRACE("(%p)\n", This);
1653 return This->NumberOfSwapChains;
1656 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1658 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1660 if(iSwapChain < This->NumberOfSwapChains) {
1661 *pSwapChain = This->swapchains[iSwapChain];
1662 IWineD3DSwapChain_AddRef(*pSwapChain);
1663 TRACE("(%p) returning %p\n", This, *pSwapChain);
1666 TRACE("Swapchain out of range\n");
1668 return WINED3DERR_INVALIDCALL;
1673 * Vertex Declaration
1675 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1676 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1678 IWineD3DVertexDeclarationImpl *object = NULL;
1679 HRESULT hr = WINED3D_OK;
1681 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1682 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1684 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1687 ERR("Out of memory\n");
1688 *ppVertexDeclaration = NULL;
1689 return WINED3DERR_OUTOFVIDEOMEMORY;
1692 object->lpVtbl = &IWineD3DVertexDeclaration_Vtbl;
1693 object->wineD3DDevice = This;
1694 object->parent = parent;
1697 *ppVertexDeclaration = (IWineD3DVertexDeclaration *)object;
1699 hr = vertexdeclaration_init(object, elements, element_count);
1702 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
1703 *ppVertexDeclaration = NULL;
1709 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1710 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1712 unsigned int idx, idx2;
1713 unsigned int offset;
1714 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1715 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1716 BOOL has_blend_idx = has_blend &&
1717 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1718 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1719 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1720 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1721 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1722 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1723 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1725 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1726 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1727 WINED3DVERTEXELEMENT *elements = NULL;
1730 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1731 if (has_blend_idx) num_blends--;
1733 /* Compute declaration size */
1734 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1735 has_psize + has_diffuse + has_specular + num_textures;
1737 /* convert the declaration */
1738 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1739 if (!elements) return ~0U;
1743 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1744 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1745 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
1747 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1748 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1749 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1752 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1753 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1755 elements[idx].usage_idx = 0;
1758 if (has_blend && (num_blends > 0)) {
1759 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1760 elements[idx].format = WINED3DFMT_A8R8G8B8;
1762 switch(num_blends) {
1763 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
1764 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
1765 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
1766 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
1768 ERR("Unexpected amount of blend values: %u\n", num_blends);
1771 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1772 elements[idx].usage_idx = 0;
1775 if (has_blend_idx) {
1776 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1777 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1778 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
1779 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1780 elements[idx].format = WINED3DFMT_A8R8G8B8;
1782 elements[idx].format = WINED3DFMT_R32_FLOAT;
1783 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
1784 elements[idx].usage_idx = 0;
1788 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1789 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
1790 elements[idx].usage_idx = 0;
1794 elements[idx].format = WINED3DFMT_R32_FLOAT;
1795 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
1796 elements[idx].usage_idx = 0;
1800 elements[idx].format = WINED3DFMT_A8R8G8B8;
1801 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1802 elements[idx].usage_idx = 0;
1806 elements[idx].format = WINED3DFMT_A8R8G8B8;
1807 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1808 elements[idx].usage_idx = 1;
1811 for (idx2 = 0; idx2 < num_textures; idx2++) {
1812 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1813 switch (numcoords) {
1814 case WINED3DFVF_TEXTUREFORMAT1:
1815 elements[idx].format = WINED3DFMT_R32_FLOAT;
1817 case WINED3DFVF_TEXTUREFORMAT2:
1818 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
1820 case WINED3DFVF_TEXTUREFORMAT3:
1821 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1823 case WINED3DFVF_TEXTUREFORMAT4:
1824 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1827 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
1828 elements[idx].usage_idx = idx2;
1832 /* Now compute offsets, and initialize the rest of the fields */
1833 for (idx = 0, offset = 0; idx < size; ++idx)
1835 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
1836 elements[idx].input_slot = 0;
1837 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1838 elements[idx].offset = offset;
1839 offset += format_desc->component_count * format_desc->component_size;
1842 *ppVertexElements = elements;
1846 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1847 WINED3DVERTEXELEMENT* elements = NULL;
1848 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1852 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1853 if (size == ~0U) return WINED3DERR_OUTOFVIDEOMEMORY;
1855 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1856 HeapFree(GetProcessHeap(), 0, elements);
1857 if (hr != S_OK) return hr;
1862 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1863 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1864 IWineD3DVertexShader **ppVertexShader, IUnknown *parent)
1866 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1867 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1868 HRESULT hr = WINED3D_OK;
1870 if (!pFunction) return WINED3DERR_INVALIDCALL;
1872 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1875 ERR("Out of memory\n");
1876 *ppVertexShader = NULL;
1877 return WINED3DERR_OUTOFVIDEOMEMORY;
1880 object->lpVtbl = &IWineD3DVertexShader_Vtbl;
1881 object->parent = parent;
1882 shader_init(&object->baseShader, iface);
1883 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1884 *ppVertexShader = (IWineD3DVertexShader *)object;
1886 TRACE("(%p) : Created vertex shader %p\n", This, *ppVertexShader);
1888 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction, output_signature);
1891 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
1892 IWineD3DVertexShader_Release(*ppVertexShader);
1893 *ppVertexShader = NULL;
1900 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1901 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1902 IWineD3DPixelShader **ppPixelShader, IUnknown *parent)
1904 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1905 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1906 HRESULT hr = WINED3D_OK;
1908 if (!pFunction) return WINED3DERR_INVALIDCALL;
1910 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1913 ERR("Out of memory\n");
1914 *ppPixelShader = NULL;
1915 return WINED3DERR_OUTOFVIDEOMEMORY;
1918 object->lpVtbl = &IWineD3DPixelShader_Vtbl;
1919 object->parent = parent;
1920 shader_init(&object->baseShader, iface);
1921 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1922 *ppPixelShader = (IWineD3DPixelShader *)object;
1924 TRACE("(%p) : Created pixel shader %p\n", This, *ppPixelShader);
1926 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction, output_signature);
1929 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
1930 IWineD3DPixelShader_Release(*ppPixelShader);
1931 *ppPixelShader = NULL;
1938 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1939 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1941 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1942 IWineD3DPaletteImpl *object;
1944 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1946 /* Create the new object */
1947 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1949 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1950 return E_OUTOFMEMORY;
1953 object->lpVtbl = &IWineD3DPalette_Vtbl;
1955 object->Flags = Flags;
1956 object->parent = Parent;
1957 object->wineD3DDevice = This;
1958 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1959 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1962 HeapFree( GetProcessHeap(), 0, object);
1963 return E_OUTOFMEMORY;
1966 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1968 IWineD3DPalette_Release((IWineD3DPalette *) object);
1972 *Palette = (IWineD3DPalette *) object;
1977 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1981 HDC dcb = NULL, dcs = NULL;
1982 WINEDDCOLORKEY colorkey;
1984 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1987 GetObjectA(hbm, sizeof(BITMAP), &bm);
1988 dcb = CreateCompatibleDC(NULL);
1990 SelectObject(dcb, hbm);
1994 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1995 * couldn't be loaded
1997 memset(&bm, 0, sizeof(bm));
2002 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5, TRUE,
2003 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL, NULL);
2005 ERR("Wine logo requested, but failed to create surface\n");
2010 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
2011 if(FAILED(hr)) goto out;
2012 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
2013 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
2015 colorkey.dwColorSpaceLowValue = 0;
2016 colorkey.dwColorSpaceHighValue = 0;
2017 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2019 /* Fill the surface with a white color to show that wined3d is there */
2020 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2033 /* Context activation is done by the caller. */
2034 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2036 /* Under DirectX you can have texture stage operations even if no texture is
2037 bound, whereas opengl will only do texture operations when a valid texture is
2038 bound. We emulate this by creating dummy textures and binding them to each
2039 texture stage, but disable all stages by default. Hence if a stage is enabled
2040 then the default texture will kick in until replaced by a SetTexture call */
2043 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2044 /* The dummy texture does not have client storage backing */
2045 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2046 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2048 for (i = 0; i < GL_LIMITS(textures); i++) {
2049 GLubyte white = 255;
2051 /* Make appropriate texture active */
2052 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2053 checkGLcall("glActiveTextureARB");
2055 /* Generate an opengl texture name */
2056 glGenTextures(1, &This->dummyTextureName[i]);
2057 checkGLcall("glGenTextures");
2058 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2060 /* Generate a dummy 2d texture (not using 1d because they cause many
2061 * DRI drivers fall back to sw) */
2062 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2063 checkGLcall("glBindTexture");
2065 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2066 checkGLcall("glTexImage2D");
2068 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2069 /* Reenable because if supported it is enabled by default */
2070 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2071 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2077 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
2078 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2080 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2081 IWineD3DSwapChainImpl *swapchain = NULL;
2086 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
2088 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2089 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2091 /* TODO: Test if OpenGL is compiled in and loaded */
2093 TRACE("(%p) : Creating stateblock\n", This);
2094 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2095 hr = IWineD3DDevice_CreateStateBlock(iface,
2097 (IWineD3DStateBlock **)&This->stateBlock,
2099 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2100 WARN("Failed to create stateblock\n");
2103 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2104 This->updateStateBlock = This->stateBlock;
2105 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2107 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2108 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2110 This->NumberOfPalettes = 1;
2111 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2112 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2113 ERR("Out of memory!\n");
2116 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2117 if(!This->palettes[0]) {
2118 ERR("Out of memory!\n");
2121 for (i = 0; i < 256; ++i) {
2122 This->palettes[0][i].peRed = 0xFF;
2123 This->palettes[0][i].peGreen = 0xFF;
2124 This->palettes[0][i].peBlue = 0xFF;
2125 This->palettes[0][i].peFlags = 0xFF;
2127 This->currentPalette = 0;
2129 /* Initialize the texture unit mapping to a 1:1 mapping */
2130 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2131 if (state < GL_LIMITS(fragment_samplers)) {
2132 This->texUnitMap[state] = state;
2133 This->rev_tex_unit_map[state] = state;
2135 This->texUnitMap[state] = -1;
2136 This->rev_tex_unit_map[state] = -1;
2140 /* Setup the implicit swapchain. This also initializes a context. */
2141 TRACE("Creating implicit swapchain\n");
2142 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2143 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2146 WARN("Failed to create implicit swapchain\n");
2150 This->NumberOfSwapChains = 1;
2151 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2152 if(!This->swapchains) {
2153 ERR("Out of memory!\n");
2156 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2158 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2159 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2160 This->render_targets[0] = swapchain->backBuffer[0];
2163 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2164 This->render_targets[0] = swapchain->frontBuffer;
2166 IWineD3DSurface_AddRef(This->render_targets[0]);
2167 This->activeContext = swapchain->context[0];
2169 /* Depth Stencil support */
2170 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2171 if (NULL != This->stencilBufferTarget) {
2172 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2175 hr = This->shader_backend->shader_alloc_private(iface);
2177 TRACE("Shader private data couldn't be allocated\n");
2180 hr = This->frag_pipe->alloc_private(iface);
2182 TRACE("Fragment pipeline private data couldn't be allocated\n");
2185 hr = This->blitter->alloc_private(iface);
2187 TRACE("Blitter private data couldn't be allocated\n");
2191 /* Set up some starting GL setup */
2193 /* Setup all the devices defaults */
2194 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2195 create_dummy_textures(This);
2199 /* Initialize the current view state */
2200 This->view_ident = 1;
2201 This->contexts[0]->last_was_rhw = 0;
2202 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2203 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2205 switch(wined3d_settings.offscreen_rendering_mode) {
2208 This->offscreenBuffer = GL_BACK;
2211 case ORM_BACKBUFFER:
2213 if(This->activeContext->aux_buffers > 0) {
2214 TRACE("Using auxilliary buffer for offscreen rendering\n");
2215 This->offscreenBuffer = GL_AUX0;
2217 TRACE("Using back buffer for offscreen rendering\n");
2218 This->offscreenBuffer = GL_BACK;
2223 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2226 /* Clear the screen */
2227 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2228 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2231 This->d3d_initialized = TRUE;
2233 if(wined3d_settings.logo) {
2234 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2236 This->highest_dirty_ps_const = 0;
2237 This->highest_dirty_vs_const = 0;
2241 HeapFree(GetProcessHeap(), 0, This->render_targets);
2242 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2243 HeapFree(GetProcessHeap(), 0, This->swapchains);
2244 This->NumberOfSwapChains = 0;
2245 if(This->palettes) {
2246 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2247 HeapFree(GetProcessHeap(), 0, This->palettes);
2249 This->NumberOfPalettes = 0;
2251 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2253 if(This->stateBlock) {
2254 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2255 This->stateBlock = NULL;
2257 if (This->blit_priv) {
2258 This->blitter->free_private(iface);
2260 if (This->fragment_priv) {
2261 This->frag_pipe->free_private(iface);
2263 if (This->shader_priv) {
2264 This->shader_backend->shader_free_private(iface);
2269 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2270 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2272 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2273 IWineD3DSwapChainImpl *swapchain = NULL;
2276 /* Setup the implicit swapchain */
2277 TRACE("Creating implicit swapchain\n");
2278 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2279 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2282 WARN("Failed to create implicit swapchain\n");
2286 This->NumberOfSwapChains = 1;
2287 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2288 if(!This->swapchains) {
2289 ERR("Out of memory!\n");
2292 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2296 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2300 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2302 IWineD3DResource_UnLoad(resource);
2303 IWineD3DResource_Release(resource);
2307 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2308 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2311 TRACE("(%p)\n", This);
2313 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2315 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2316 * it was created. Thus make sure a context is active for the glDelete* calls
2318 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
2320 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2322 /* Unload resources */
2323 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2325 TRACE("Deleting high order patches\n");
2326 for(i = 0; i < PATCHMAP_SIZE; i++) {
2327 struct list *e1, *e2;
2328 struct WineD3DRectPatch *patch;
2329 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2330 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2331 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2335 /* Delete the palette conversion shader if it is around */
2336 if(This->paletteConversionShader) {
2338 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2340 This->paletteConversionShader = 0;
2343 /* Delete the pbuffer context if there is any */
2344 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2346 /* Delete the mouse cursor texture */
2347 if(This->cursorTexture) {
2349 glDeleteTextures(1, &This->cursorTexture);
2351 This->cursorTexture = 0;
2354 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2355 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2357 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2358 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2361 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2362 * private data, it might contain opengl pointers
2364 if(This->depth_blt_texture) {
2366 glDeleteTextures(1, &This->depth_blt_texture);
2368 This->depth_blt_texture = 0;
2370 if (This->depth_blt_rb) {
2372 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2374 This->depth_blt_rb = 0;
2375 This->depth_blt_rb_w = 0;
2376 This->depth_blt_rb_h = 0;
2379 /* Release the update stateblock */
2380 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2381 if(This->updateStateBlock != This->stateBlock)
2382 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2384 This->updateStateBlock = NULL;
2386 { /* because were not doing proper internal refcounts releasing the primary state block
2387 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2388 to set this->stateBlock = NULL; first */
2389 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2390 This->stateBlock = NULL;
2392 /* Release the stateblock */
2393 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2394 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2398 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2399 This->blitter->free_private(iface);
2400 This->frag_pipe->free_private(iface);
2401 This->shader_backend->shader_free_private(iface);
2403 /* Release the buffers (with sanity checks)*/
2404 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2405 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2406 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2407 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2409 This->stencilBufferTarget = NULL;
2411 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2412 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2413 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2415 TRACE("Setting rendertarget to NULL\n");
2416 This->render_targets[0] = NULL;
2418 if (This->auto_depth_stencil_buffer) {
2419 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2420 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2422 This->auto_depth_stencil_buffer = NULL;
2425 for(i=0; i < This->NumberOfSwapChains; i++) {
2426 TRACE("Releasing the implicit swapchain %d\n", i);
2427 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2428 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2432 HeapFree(GetProcessHeap(), 0, This->swapchains);
2433 This->swapchains = NULL;
2434 This->NumberOfSwapChains = 0;
2436 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2437 HeapFree(GetProcessHeap(), 0, This->palettes);
2438 This->palettes = NULL;
2439 This->NumberOfPalettes = 0;
2441 HeapFree(GetProcessHeap(), 0, This->render_targets);
2442 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2443 This->render_targets = NULL;
2444 This->draw_buffers = NULL;
2446 This->d3d_initialized = FALSE;
2450 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2451 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2454 for(i=0; i < This->NumberOfSwapChains; i++) {
2455 TRACE("Releasing the implicit swapchain %d\n", i);
2456 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2457 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2461 HeapFree(GetProcessHeap(), 0, This->swapchains);
2462 This->swapchains = NULL;
2463 This->NumberOfSwapChains = 0;
2467 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2468 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2469 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2471 * There is no way to deactivate thread safety once it is enabled.
2473 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2474 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2476 /*For now just store the flag(needed in case of ddraw) */
2477 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2482 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2483 const WINED3DDISPLAYMODE* pMode) {
2485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2487 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &GLINFO_LOCATION);
2490 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2492 /* Resize the screen even without a window:
2493 * The app could have unset it with SetCooperativeLevel, but not called
2494 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2495 * but we don't have any hwnd
2498 memset(&devmode, 0, sizeof(devmode));
2499 devmode.dmSize = sizeof(devmode);
2500 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2501 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2502 devmode.dmPelsWidth = pMode->Width;
2503 devmode.dmPelsHeight = pMode->Height;
2505 devmode.dmDisplayFrequency = pMode->RefreshRate;
2506 if (pMode->RefreshRate != 0) {
2507 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2510 /* Only change the mode if necessary */
2511 if( (This->ddraw_width == pMode->Width) &&
2512 (This->ddraw_height == pMode->Height) &&
2513 (This->ddraw_format == pMode->Format) &&
2514 (pMode->RefreshRate == 0) ) {
2518 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2519 if (ret != DISP_CHANGE_SUCCESSFUL) {
2520 if(devmode.dmDisplayFrequency != 0) {
2521 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2522 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2523 devmode.dmDisplayFrequency = 0;
2524 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2526 if(ret != DISP_CHANGE_SUCCESSFUL) {
2527 return WINED3DERR_NOTAVAILABLE;
2531 /* Store the new values */
2532 This->ddraw_width = pMode->Width;
2533 This->ddraw_height = pMode->Height;
2534 This->ddraw_format = pMode->Format;
2536 /* And finally clip mouse to our screen */
2537 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2538 ClipCursor(&clip_rc);
2543 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2544 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2545 *ppD3D= This->wineD3D;
2546 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2547 IWineD3D_AddRef(*ppD3D);
2551 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2552 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2554 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2555 (This->adapter->TextureRam/(1024*1024)),
2556 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2557 /* return simulated texture memory left */
2558 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2562 * Get / Set Stream Source
2564 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2565 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2567 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2568 IWineD3DBuffer *oldSrc;
2570 if (StreamNumber >= MAX_STREAMS) {
2571 WARN("Stream out of range %d\n", StreamNumber);
2572 return WINED3DERR_INVALIDCALL;
2573 } else if(OffsetInBytes & 0x3) {
2574 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2575 return WINED3DERR_INVALIDCALL;
2578 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2579 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2581 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2583 if(oldSrc == pStreamData &&
2584 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2585 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2586 TRACE("Application is setting the old values over, nothing to do\n");
2590 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2592 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2593 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2596 /* Handle recording of state blocks */
2597 if (This->isRecordingState) {
2598 TRACE("Recording... not performing anything\n");
2599 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2600 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2604 if (pStreamData != NULL) {
2605 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2606 IWineD3DBuffer_AddRef(pStreamData);
2608 if (oldSrc != NULL) {
2609 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2610 IWineD3DBuffer_Release(oldSrc);
2613 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2618 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2619 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2621 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2623 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2624 This->stateBlock->streamSource[StreamNumber],
2625 This->stateBlock->streamOffset[StreamNumber],
2626 This->stateBlock->streamStride[StreamNumber]);
2628 if (StreamNumber >= MAX_STREAMS) {
2629 WARN("Stream out of range %d\n", StreamNumber);
2630 return WINED3DERR_INVALIDCALL;
2632 *pStream = This->stateBlock->streamSource[StreamNumber];
2633 *pStride = This->stateBlock->streamStride[StreamNumber];
2635 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2638 if (*pStream != NULL) {
2639 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2644 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2645 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2646 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2647 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2649 /* Verify input at least in d3d9 this is invalid*/
2650 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2651 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2652 return WINED3DERR_INVALIDCALL;
2654 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2655 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2656 return WINED3DERR_INVALIDCALL;
2659 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2660 return WINED3DERR_INVALIDCALL;
2663 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2664 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2666 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2667 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2669 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2670 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2671 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2677 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2678 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2680 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2681 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2683 TRACE("(%p) : returning %d\n", This, *Divider);
2689 * Get / Set & Multiply Transform
2691 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2692 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2694 /* Most of this routine, comments included copied from ddraw tree initially: */
2695 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2697 /* Handle recording of state blocks */
2698 if (This->isRecordingState) {
2699 TRACE("Recording... not performing anything\n");
2700 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2701 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2706 * If the new matrix is the same as the current one,
2707 * we cut off any further processing. this seems to be a reasonable
2708 * optimization because as was noticed, some apps (warcraft3 for example)
2709 * tend towards setting the same matrix repeatedly for some reason.
2711 * From here on we assume that the new matrix is different, wherever it matters.
2713 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2714 TRACE("The app is setting the same matrix over again\n");
2717 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2721 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2722 where ViewMat = Camera space, WorldMat = world space.
2724 In OpenGL, camera and world space is combined into GL_MODELVIEW
2725 matrix. The Projection matrix stay projection matrix.
2728 /* Capture the times we can just ignore the change for now */
2729 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2730 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2731 /* Handled by the state manager */
2734 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2738 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2739 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2740 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2741 *pMatrix = This->stateBlock->transforms[State];
2745 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2746 const WINED3DMATRIX *mat = NULL;
2749 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2750 * below means it will be recorded in a state block change, but it
2751 * works regardless where it is recorded.
2752 * If this is found to be wrong, change to StateBlock.
2754 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2755 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2757 if (State <= HIGHEST_TRANSFORMSTATE)
2759 mat = &This->updateStateBlock->transforms[State];
2761 FIXME("Unhandled transform state!!\n");
2764 multiply_matrix(&temp, mat, pMatrix);
2766 /* Apply change via set transform - will reapply to eg. lights this way */
2767 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2773 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2774 you can reference any indexes you want as long as that number max are enabled at any
2775 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2776 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2777 but when recording, just build a chain pretty much of commands to be replayed. */
2779 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2781 PLIGHTINFOEL *object = NULL;
2782 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2785 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2786 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2788 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2792 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2793 return WINED3DERR_INVALIDCALL;
2796 switch(pLight->Type) {
2797 case WINED3DLIGHT_POINT:
2798 case WINED3DLIGHT_SPOT:
2799 case WINED3DLIGHT_PARALLELPOINT:
2800 case WINED3DLIGHT_GLSPOT:
2801 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2804 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2806 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2807 return WINED3DERR_INVALIDCALL;
2811 case WINED3DLIGHT_DIRECTIONAL:
2812 /* Ignores attenuation */
2816 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2817 return WINED3DERR_INVALIDCALL;
2820 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2821 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2822 if(object->OriginalIndex == Index) break;
2827 TRACE("Adding new light\n");
2828 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2830 ERR("Out of memory error when allocating a light\n");
2831 return E_OUTOFMEMORY;
2833 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2834 object->glIndex = -1;
2835 object->OriginalIndex = Index;
2836 object->changed = TRUE;
2839 /* Initialize the object */
2840 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,
2841 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2842 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2843 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2844 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2845 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2846 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2848 /* Save away the information */
2849 object->OriginalParms = *pLight;
2851 switch (pLight->Type) {
2852 case WINED3DLIGHT_POINT:
2854 object->lightPosn[0] = pLight->Position.x;
2855 object->lightPosn[1] = pLight->Position.y;
2856 object->lightPosn[2] = pLight->Position.z;
2857 object->lightPosn[3] = 1.0f;
2858 object->cutoff = 180.0f;
2862 case WINED3DLIGHT_DIRECTIONAL:
2864 object->lightPosn[0] = -pLight->Direction.x;
2865 object->lightPosn[1] = -pLight->Direction.y;
2866 object->lightPosn[2] = -pLight->Direction.z;
2867 object->lightPosn[3] = 0.0f;
2868 object->exponent = 0.0f;
2869 object->cutoff = 180.0f;
2872 case WINED3DLIGHT_SPOT:
2874 object->lightPosn[0] = pLight->Position.x;
2875 object->lightPosn[1] = pLight->Position.y;
2876 object->lightPosn[2] = pLight->Position.z;
2877 object->lightPosn[3] = 1.0f;
2880 object->lightDirn[0] = pLight->Direction.x;
2881 object->lightDirn[1] = pLight->Direction.y;
2882 object->lightDirn[2] = pLight->Direction.z;
2883 object->lightDirn[3] = 1.0f;
2886 * opengl-ish and d3d-ish spot lights use too different models for the
2887 * light "intensity" as a function of the angle towards the main light direction,
2888 * so we only can approximate very roughly.
2889 * however spot lights are rather rarely used in games (if ever used at all).
2890 * furthermore if still used, probably nobody pays attention to such details.
2892 if (pLight->Falloff == 0) {
2893 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2894 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2895 * will always be 1.0 for both of them, and we don't have to care for the
2896 * rest of the rather complex calculation
2898 object->exponent = 0.0f;
2900 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2901 if (rho < 0.0001f) rho = 0.0001f;
2902 object->exponent = -0.3f/logf(cosf(rho/2));
2904 if (object->exponent > 128.0f)
2906 object->exponent = 128.0f;
2908 object->cutoff = pLight->Phi*90/M_PI;
2914 FIXME("Unrecognized light type %d\n", pLight->Type);
2917 /* Update the live definitions if the light is currently assigned a glIndex */
2918 if (object->glIndex != -1 && !This->isRecordingState) {
2919 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2924 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2925 PLIGHTINFOEL *lightInfo = NULL;
2926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2927 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2929 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2931 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2932 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2933 if(lightInfo->OriginalIndex == Index) break;
2937 if (lightInfo == NULL) {
2938 TRACE("Light information requested but light not defined\n");
2939 return WINED3DERR_INVALIDCALL;
2942 *pLight = lightInfo->OriginalParms;
2947 * Get / Set Light Enable
2948 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2950 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2951 PLIGHTINFOEL *lightInfo = NULL;
2952 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2953 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2955 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2957 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2958 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2959 if(lightInfo->OriginalIndex == Index) break;
2962 TRACE("Found light: %p\n", lightInfo);
2964 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2965 if (lightInfo == NULL) {
2967 TRACE("Light enabled requested but light not defined, so defining one!\n");
2968 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2970 /* Search for it again! Should be fairly quick as near head of list */
2971 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2972 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2973 if(lightInfo->OriginalIndex == Index) break;
2976 if (lightInfo == NULL) {
2977 FIXME("Adding default lights has failed dismally\n");
2978 return WINED3DERR_INVALIDCALL;
2982 lightInfo->enabledChanged = TRUE;
2984 if(lightInfo->glIndex != -1) {
2985 if(!This->isRecordingState) {
2986 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2989 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2990 lightInfo->glIndex = -1;
2992 TRACE("Light already disabled, nothing to do\n");
2994 lightInfo->enabled = FALSE;
2996 lightInfo->enabled = TRUE;
2997 if (lightInfo->glIndex != -1) {
2999 TRACE("Nothing to do as light was enabled\n");
3002 /* Find a free gl light */
3003 for(i = 0; i < This->maxConcurrentLights; i++) {
3004 if(This->updateStateBlock->activeLights[i] == NULL) {
3005 This->updateStateBlock->activeLights[i] = lightInfo;
3006 lightInfo->glIndex = i;
3010 if(lightInfo->glIndex == -1) {
3011 /* Our tests show that Windows returns D3D_OK in this situation, even with
3012 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3013 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3014 * as well for those lights.
3016 * TODO: Test how this affects rendering
3018 WARN("Too many concurrently active lights\n");
3022 /* i == lightInfo->glIndex */
3023 if(!This->isRecordingState) {
3024 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3032 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3034 PLIGHTINFOEL *lightInfo = NULL;
3035 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3037 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3038 TRACE("(%p) : for idx(%d)\n", This, Index);
3040 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3041 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3042 if(lightInfo->OriginalIndex == Index) break;
3046 if (lightInfo == NULL) {
3047 TRACE("Light enabled state requested but light not defined\n");
3048 return WINED3DERR_INVALIDCALL;
3050 /* true is 128 according to SetLightEnable */
3051 *pEnable = lightInfo->enabled ? 128 : 0;
3056 * Get / Set Clip Planes
3058 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3059 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3060 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3062 /* Validate Index */
3063 if (Index >= GL_LIMITS(clipplanes)) {
3064 TRACE("Application has requested clipplane this device doesn't support\n");
3065 return WINED3DERR_INVALIDCALL;
3068 This->updateStateBlock->changed.clipplane |= 1 << Index;
3070 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3071 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3072 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3073 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3074 TRACE("Application is setting old values over, nothing to do\n");
3078 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3079 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3080 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3081 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3083 /* Handle recording of state blocks */
3084 if (This->isRecordingState) {
3085 TRACE("Recording... not performing anything\n");
3089 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3094 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3096 TRACE("(%p) : for idx %d\n", This, Index);
3098 /* Validate Index */
3099 if (Index >= GL_LIMITS(clipplanes)) {
3100 TRACE("Application has requested clipplane this device doesn't support\n");
3101 return WINED3DERR_INVALIDCALL;
3104 pPlane[0] = This->stateBlock->clipplane[Index][0];
3105 pPlane[1] = This->stateBlock->clipplane[Index][1];
3106 pPlane[2] = This->stateBlock->clipplane[Index][2];
3107 pPlane[3] = This->stateBlock->clipplane[Index][3];
3112 * Get / Set Clip Plane Status
3113 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3115 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3116 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3117 FIXME("(%p) : stub\n", This);
3118 if (NULL == pClipStatus) {
3119 return WINED3DERR_INVALIDCALL;
3121 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3122 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3126 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3127 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3128 FIXME("(%p) : stub\n", This);
3129 if (NULL == pClipStatus) {
3130 return WINED3DERR_INVALIDCALL;
3132 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3133 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3138 * Get / Set Material
3140 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3141 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3143 This->updateStateBlock->changed.material = TRUE;
3144 This->updateStateBlock->material = *pMaterial;
3146 /* Handle recording of state blocks */
3147 if (This->isRecordingState) {
3148 TRACE("Recording... not performing anything\n");
3152 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3156 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3157 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3158 *pMaterial = This->updateStateBlock->material;
3159 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3160 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3161 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3162 pMaterial->Ambient.b, pMaterial->Ambient.a);
3163 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3164 pMaterial->Specular.b, pMaterial->Specular.a);
3165 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3166 pMaterial->Emissive.b, pMaterial->Emissive.a);
3167 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3175 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DBuffer* pIndexData, WINED3DFORMAT fmt) {
3176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3177 IWineD3DBuffer *oldIdxs;
3179 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3180 oldIdxs = This->updateStateBlock->pIndexData;
3182 This->updateStateBlock->changed.indices = TRUE;
3183 This->updateStateBlock->pIndexData = pIndexData;
3184 This->updateStateBlock->IndexFmt = fmt;
3186 /* Handle recording of state blocks */
3187 if (This->isRecordingState) {
3188 TRACE("Recording... not performing anything\n");
3189 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
3190 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
3194 if(oldIdxs != pIndexData) {
3195 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3197 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
3198 IWineD3DBuffer_AddRef(pIndexData);
3201 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
3202 IWineD3DBuffer_Release(oldIdxs);
3209 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DBuffer** ppIndexData) {
3210 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3212 *ppIndexData = This->stateBlock->pIndexData;
3214 /* up ref count on ppindexdata */
3216 IWineD3DBuffer_AddRef(*ppIndexData);
3217 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3219 TRACE("(%p) No index data set\n", This);
3221 TRACE("Returning %p\n", *ppIndexData);
3226 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3227 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3228 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3229 TRACE("(%p)->(%d)\n", This, BaseIndex);
3231 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3232 TRACE("Application is setting the old value over, nothing to do\n");
3236 This->updateStateBlock->baseVertexIndex = BaseIndex;
3238 if (This->isRecordingState) {
3239 TRACE("Recording... not performing anything\n");
3242 /* The base vertex index affects the stream sources */
3243 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3247 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3248 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3249 TRACE("(%p) : base_index %p\n", This, base_index);
3251 *base_index = This->stateBlock->baseVertexIndex;
3253 TRACE("Returning %u\n", *base_index);
3259 * Get / Set Viewports
3261 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3262 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3264 TRACE("(%p)\n", This);
3265 This->updateStateBlock->changed.viewport = TRUE;
3266 This->updateStateBlock->viewport = *pViewport;
3268 /* Handle recording of state blocks */
3269 if (This->isRecordingState) {
3270 TRACE("Recording... not performing anything\n");
3274 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3275 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3277 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3282 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3283 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3284 TRACE("(%p)\n", This);
3285 *pViewport = This->stateBlock->viewport;
3290 * Get / Set Render States
3291 * TODO: Verify against dx9 definitions
3293 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3295 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3296 DWORD oldValue = This->stateBlock->renderState[State];
3298 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3300 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3301 This->updateStateBlock->renderState[State] = Value;
3303 /* Handle recording of state blocks */
3304 if (This->isRecordingState) {
3305 TRACE("Recording... not performing anything\n");
3309 /* Compared here and not before the assignment to allow proper stateblock recording */
3310 if(Value == oldValue) {
3311 TRACE("Application is setting the old value over, nothing to do\n");
3313 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3319 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3321 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3322 *pValue = This->stateBlock->renderState[State];
3327 * Get / Set Sampler States
3328 * TODO: Verify against dx9 definitions
3331 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3332 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3335 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3336 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3338 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3339 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3342 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3343 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3344 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3347 * SetSampler is designed to allow for more than the standard up to 8 textures
3348 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3349 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3351 * http://developer.nvidia.com/object/General_FAQ.html#t6
3353 * There are two new settings for GForce
3355 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3356 * and the texture one:
3357 * GL_MAX_TEXTURE_COORDS_ARB.
3358 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3361 oldValue = This->stateBlock->samplerState[Sampler][Type];
3362 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3363 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3365 /* Handle recording of state blocks */
3366 if (This->isRecordingState) {
3367 TRACE("Recording... not performing anything\n");
3371 if(oldValue == Value) {
3372 TRACE("Application is setting the old value over, nothing to do\n");
3376 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3381 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3382 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3384 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3385 This, Sampler, debug_d3dsamplerstate(Type), Type);
3387 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3388 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3391 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3392 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3393 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3395 *Value = This->stateBlock->samplerState[Sampler][Type];
3396 TRACE("(%p) : Returning %#x\n", This, *Value);
3401 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3404 This->updateStateBlock->changed.scissorRect = TRUE;
3405 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3406 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3409 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3411 if(This->isRecordingState) {
3412 TRACE("Recording... not performing anything\n");
3416 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3421 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3422 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3424 *pRect = This->updateStateBlock->scissorRect;
3425 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3429 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3430 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3431 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3433 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3435 This->updateStateBlock->vertexDecl = pDecl;
3436 This->updateStateBlock->changed.vertexDecl = TRUE;
3438 if (This->isRecordingState) {
3439 TRACE("Recording... not performing anything\n");
3441 } else if(pDecl == oldDecl) {
3442 /* Checked after the assignment to allow proper stateblock recording */
3443 TRACE("Application is setting the old declaration over, nothing to do\n");
3447 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3451 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3452 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3454 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3456 *ppDecl = This->stateBlock->vertexDecl;
3457 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3461 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3462 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3463 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3465 This->updateStateBlock->vertexShader = pShader;
3466 This->updateStateBlock->changed.vertexShader = TRUE;
3468 if (This->isRecordingState) {
3469 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3470 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3471 TRACE("Recording... not performing anything\n");
3473 } else if(oldShader == pShader) {
3474 /* Checked here to allow proper stateblock recording */
3475 TRACE("App is setting the old shader over, nothing to do\n");
3479 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3480 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3481 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3483 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3488 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3489 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3491 if (NULL == ppShader) {
3492 return WINED3DERR_INVALIDCALL;
3494 *ppShader = This->stateBlock->vertexShader;
3495 if( NULL != *ppShader)
3496 IWineD3DVertexShader_AddRef(*ppShader);
3498 TRACE("(%p) : returning %p\n", This, *ppShader);
3502 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3503 IWineD3DDevice *iface,
3505 CONST BOOL *srcData,
3508 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3509 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3511 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3512 iface, srcData, start, count);
3514 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3516 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3517 for (i = 0; i < cnt; i++)
3518 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3520 for (i = start; i < cnt + start; ++i) {
3521 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3524 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3529 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3530 IWineD3DDevice *iface,
3535 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3536 int cnt = min(count, MAX_CONST_B - start);
3538 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3539 iface, dstData, start, count);
3541 if (dstData == NULL || cnt < 0)
3542 return WINED3DERR_INVALIDCALL;
3544 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3548 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3549 IWineD3DDevice *iface,
3554 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3555 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3557 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3558 iface, srcData, start, count);
3560 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3562 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3563 for (i = 0; i < cnt; i++)
3564 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3565 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3567 for (i = start; i < cnt + start; ++i) {
3568 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3571 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3576 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3577 IWineD3DDevice *iface,
3582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3583 int cnt = min(count, MAX_CONST_I - start);
3585 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3586 iface, dstData, start, count);
3588 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3589 return WINED3DERR_INVALIDCALL;
3591 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3595 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3596 IWineD3DDevice *iface,
3598 CONST float *srcData,
3601 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3604 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3605 iface, srcData, start, count);
3607 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3608 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3609 return WINED3DERR_INVALIDCALL;
3611 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3613 for (i = 0; i < count; i++)
3614 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3615 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3618 if (!This->isRecordingState)
3620 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3621 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3624 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3625 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3630 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3631 IWineD3DDevice *iface,
3636 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3637 int cnt = min(count, This->d3d_vshader_constantF - start);
3639 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3640 iface, dstData, start, count);
3642 if (dstData == NULL || cnt < 0)
3643 return WINED3DERR_INVALIDCALL;
3645 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3649 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3651 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3653 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3657 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3658 int i = This->rev_tex_unit_map[unit];
3659 int j = This->texUnitMap[stage];
3661 This->texUnitMap[stage] = unit;
3662 if (i != -1 && i != stage) {
3663 This->texUnitMap[i] = -1;
3666 This->rev_tex_unit_map[unit] = stage;
3667 if (j != -1 && j != unit) {
3668 This->rev_tex_unit_map[j] = -1;
3672 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3675 This->fixed_function_usage_map = 0;
3676 for (i = 0; i < MAX_TEXTURES; ++i) {
3677 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3678 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3679 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3680 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3681 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3682 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3683 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3684 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3686 if (color_op == WINED3DTOP_DISABLE) {
3687 /* Not used, and disable higher stages */
3691 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3692 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3693 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3694 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3695 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3696 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3697 This->fixed_function_usage_map |= (1 << i);
3700 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3701 This->fixed_function_usage_map |= (1 << (i + 1));
3706 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3707 unsigned int i, tex;
3710 device_update_fixed_function_usage_map(This);
3711 ffu_map = This->fixed_function_usage_map;
3713 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3714 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3715 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3717 if (!(ffu_map & 1)) continue;
3719 if (This->texUnitMap[i] != i) {
3720 device_map_stage(This, i, i);
3721 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3722 markTextureStagesDirty(This, i);
3728 /* Now work out the mapping */
3730 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3732 if (!(ffu_map & 1)) continue;
3734 if (This->texUnitMap[i] != tex) {
3735 device_map_stage(This, i, tex);
3736 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3737 markTextureStagesDirty(This, i);
3744 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3745 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3746 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3749 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3750 if (sampler_type[i] && This->texUnitMap[i] != i)
3752 device_map_stage(This, i, i);
3753 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3754 if (i < MAX_TEXTURES) {
3755 markTextureStagesDirty(This, i);
3761 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3762 const DWORD *vshader_sampler_tokens, int unit)
3764 int current_mapping = This->rev_tex_unit_map[unit];
3766 if (current_mapping == -1) {
3767 /* Not currently used */
3771 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3772 /* Used by a fragment sampler */
3774 if (!pshader_sampler_tokens) {
3775 /* No pixel shader, check fixed function */
3776 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3779 /* Pixel shader, check the shader's sampler map */
3780 return !pshader_sampler_tokens[current_mapping];
3783 /* Used by a vertex sampler */
3784 return !vshader_sampler_tokens[current_mapping];
3787 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3788 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3789 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3790 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3791 int start = GL_LIMITS(combined_samplers) - 1;
3795 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3797 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3798 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3799 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3802 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3803 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3804 if (vshader_sampler_type[i])
3806 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3808 /* Already mapped somewhere */
3812 while (start >= 0) {
3813 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3815 device_map_stage(This, vsampler_idx, start);
3816 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3828 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3829 BOOL vs = use_vs(This->stateBlock);
3830 BOOL ps = use_ps(This->stateBlock);
3833 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3834 * that would be really messy and require shader recompilation
3835 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3836 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3839 device_map_psamplers(This);
3841 device_map_fixed_function_samplers(This);
3845 device_map_vsamplers(This, ps);
3849 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3850 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3851 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3852 This->updateStateBlock->pixelShader = pShader;
3853 This->updateStateBlock->changed.pixelShader = TRUE;
3855 /* Handle recording of state blocks */
3856 if (This->isRecordingState) {
3857 TRACE("Recording... not performing anything\n");
3860 if (This->isRecordingState) {
3861 TRACE("Recording... not performing anything\n");
3862 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3863 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3867 if(pShader == oldShader) {
3868 TRACE("App is setting the old pixel shader over, nothing to do\n");
3872 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3873 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3875 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3876 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3881 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3882 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3884 if (NULL == ppShader) {
3885 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3886 return WINED3DERR_INVALIDCALL;
3889 *ppShader = This->stateBlock->pixelShader;
3890 if (NULL != *ppShader) {
3891 IWineD3DPixelShader_AddRef(*ppShader);
3893 TRACE("(%p) : returning %p\n", This, *ppShader);
3897 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3898 IWineD3DDevice *iface,
3900 CONST BOOL *srcData,
3903 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3904 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3906 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3907 iface, srcData, start, count);
3909 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3911 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3912 for (i = 0; i < cnt; i++)
3913 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3915 for (i = start; i < cnt + start; ++i) {
3916 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3919 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3924 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3925 IWineD3DDevice *iface,
3930 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3931 int cnt = min(count, MAX_CONST_B - start);
3933 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3934 iface, dstData, start, count);
3936 if (dstData == NULL || cnt < 0)
3937 return WINED3DERR_INVALIDCALL;
3939 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3943 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3944 IWineD3DDevice *iface,
3949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3950 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3952 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3953 iface, srcData, start, count);
3955 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3957 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3958 for (i = 0; i < cnt; i++)
3959 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3960 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3962 for (i = start; i < cnt + start; ++i) {
3963 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3966 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3971 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3972 IWineD3DDevice *iface,
3977 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3978 int cnt = min(count, MAX_CONST_I - start);
3980 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3981 iface, dstData, start, count);
3983 if (dstData == NULL || cnt < 0)
3984 return WINED3DERR_INVALIDCALL;
3986 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3990 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3991 IWineD3DDevice *iface,
3993 CONST float *srcData,
3996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3999 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4000 iface, srcData, start, count);
4002 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4003 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
4004 return WINED3DERR_INVALIDCALL;
4006 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4008 for (i = 0; i < count; i++)
4009 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4010 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4013 if (!This->isRecordingState)
4015 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
4016 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4019 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
4020 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
4025 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4026 IWineD3DDevice *iface,
4031 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4032 int cnt = min(count, This->d3d_pshader_constantF - start);
4034 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4035 iface, dstData, start, count);
4037 if (dstData == NULL || cnt < 0)
4038 return WINED3DERR_INVALIDCALL;
4040 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4044 /* Context activation is done by the caller. */
4045 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4046 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4047 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
4050 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4053 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4057 if (stream_info->elements[WINED3D_FFP_NORMAL].data)
4059 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4062 if (!stream_info->elements[WINED3D_FFP_POSITION].data)
4064 ERR("Source has no position mask\n");
4065 return WINED3DERR_INVALIDCALL;
4068 /* We might access VBOs from this code, so hold the lock */
4071 if (dest->resource.allocatedMemory == NULL) {
4072 buffer_get_sysmem(dest);
4075 /* Get a pointer into the destination vbo(create one if none exists) and
4076 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4078 if (!dest->buffer_object && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT))
4080 dest->flags |= WINED3D_BUFFER_CREATEBO;
4081 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
4084 if (dest->buffer_object)
4086 unsigned char extrabytes = 0;
4087 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4088 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4089 * this may write 4 extra bytes beyond the area that should be written
4091 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4092 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4093 if(!dest_conv_addr) {
4094 ERR("Out of memory\n");
4095 /* Continue without storing converted vertices */
4097 dest_conv = dest_conv_addr;
4101 * a) WINED3DRS_CLIPPING is enabled
4102 * b) WINED3DVOP_CLIP is passed
4104 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4105 static BOOL warned = FALSE;
4107 * The clipping code is not quite correct. Some things need
4108 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4109 * so disable clipping for now.
4110 * (The graphics in Half-Life are broken, and my processvertices
4111 * test crashes with IDirect3DDevice3)
4117 FIXME("Clipping is broken and disabled for now\n");
4119 } else doClip = FALSE;
4120 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4122 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4125 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4126 WINED3DTS_PROJECTION,
4128 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4129 WINED3DTS_WORLDMATRIX(0),
4132 TRACE("View mat:\n");
4133 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);
4134 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);
4135 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);
4136 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);
4138 TRACE("Proj mat:\n");
4139 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);
4140 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);
4141 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);
4142 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);
4144 TRACE("World mat:\n");
4145 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);
4146 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);
4147 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);
4148 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);
4150 /* Get the viewport */
4151 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4152 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4153 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4155 multiply_matrix(&mat,&view_mat,&world_mat);
4156 multiply_matrix(&mat,&proj_mat,&mat);
4158 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4160 for (i = 0; i < dwCount; i+= 1) {
4161 unsigned int tex_index;
4163 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4164 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4165 /* The position first */
4166 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
4167 const float *p = (const float *)(element->data + i * element->stride);
4169 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4171 /* Multiplication with world, view and projection matrix */
4172 x = (p[0] * mat.u.s._11) + (p[1] * mat.u.s._21) + (p[2] * mat.u.s._31) + (1.0f * mat.u.s._41);
4173 y = (p[0] * mat.u.s._12) + (p[1] * mat.u.s._22) + (p[2] * mat.u.s._32) + (1.0f * mat.u.s._42);
4174 z = (p[0] * mat.u.s._13) + (p[1] * mat.u.s._23) + (p[2] * mat.u.s._33) + (1.0f * mat.u.s._43);
4175 rhw = (p[0] * mat.u.s._14) + (p[1] * mat.u.s._24) + (p[2] * mat.u.s._34) + (1.0f * mat.u.s._44);
4177 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4179 /* WARNING: The following things are taken from d3d7 and were not yet checked
4180 * against d3d8 or d3d9!
4183 /* Clipping conditions: From msdn
4185 * A vertex is clipped if it does not match the following requirements
4189 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4191 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4192 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4197 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4198 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4201 /* "Normal" viewport transformation (not clipped)
4202 * 1) The values are divided by rhw
4203 * 2) The y axis is negative, so multiply it with -1
4204 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4205 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4206 * 4) Multiply x with Width/2 and add Width/2
4207 * 5) The same for the height
4208 * 6) Add the viewpoint X and Y to the 2D coordinates and
4209 * The minimum Z value to z
4210 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4212 * Well, basically it's simply a linear transformation into viewport
4224 z *= vp.MaxZ - vp.MinZ;
4226 x += vp.Width / 2 + vp.X;
4227 y += vp.Height / 2 + vp.Y;
4232 /* That vertex got clipped
4233 * Contrary to OpenGL it is not dropped completely, it just
4234 * undergoes a different calculation.
4236 TRACE("Vertex got clipped\n");
4243 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4244 * outside of the main vertex buffer memory. That needs some more
4249 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4252 ( (float *) dest_ptr)[0] = x;
4253 ( (float *) dest_ptr)[1] = y;
4254 ( (float *) dest_ptr)[2] = z;
4255 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4257 dest_ptr += 3 * sizeof(float);
4259 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4260 dest_ptr += sizeof(float);
4265 ( (float *) dest_conv)[0] = x * w;
4266 ( (float *) dest_conv)[1] = y * w;
4267 ( (float *) dest_conv)[2] = z * w;
4268 ( (float *) dest_conv)[3] = w;
4270 dest_conv += 3 * sizeof(float);
4272 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4273 dest_conv += sizeof(float);
4277 if (DestFVF & WINED3DFVF_PSIZE) {
4278 dest_ptr += sizeof(DWORD);
4279 if(dest_conv) dest_conv += sizeof(DWORD);
4281 if (DestFVF & WINED3DFVF_NORMAL) {
4282 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4283 const float *normal = (const float *)(element->data + i * element->stride);
4284 /* AFAIK this should go into the lighting information */
4285 FIXME("Didn't expect the destination to have a normal\n");
4286 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4288 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4292 if (DestFVF & WINED3DFVF_DIFFUSE) {
4293 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4294 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4296 static BOOL warned = FALSE;
4299 ERR("No diffuse color in source, but destination has one\n");
4303 *( (DWORD *) dest_ptr) = 0xffffffff;
4304 dest_ptr += sizeof(DWORD);
4307 *( (DWORD *) dest_conv) = 0xffffffff;
4308 dest_conv += sizeof(DWORD);
4312 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4314 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4315 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4316 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4317 dest_conv += sizeof(DWORD);
4322 if (DestFVF & WINED3DFVF_SPECULAR) {
4323 /* What's the color value in the feedback buffer? */
4324 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4325 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4327 static BOOL warned = FALSE;
4330 ERR("No specular color in source, but destination has one\n");
4334 *( (DWORD *) dest_ptr) = 0xFF000000;
4335 dest_ptr += sizeof(DWORD);
4338 *( (DWORD *) dest_conv) = 0xFF000000;
4339 dest_conv += sizeof(DWORD);
4343 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4345 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4346 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4347 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4348 dest_conv += sizeof(DWORD);
4353 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4354 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4355 const float *tex_coord = (const float *)(element->data + i * element->stride);
4357 ERR("No source texture, but destination requests one\n");
4358 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4359 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4362 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4364 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4371 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4372 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4373 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4374 dwCount * get_flexible_vertex_size(DestFVF),
4376 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4377 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4384 #undef copy_and_next
4386 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4387 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4391 struct wined3d_stream_info stream_info;
4392 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4393 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4396 ERR("Output vertex declaration not implemented yet\n");
4399 /* Need any context to write to the vbo. */
4400 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
4402 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4403 * control the streamIsUP flag, thus restore it afterwards.
4405 This->stateBlock->streamIsUP = FALSE;
4406 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4407 This->stateBlock->streamIsUP = streamWasUP;
4409 if(vbo || SrcStartIndex) {
4411 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4412 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4414 * Also get the start index in, but only loop over all elements if there's something to add at all.
4416 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4418 struct wined3d_stream_info_element *e = &stream_info.elements[i];
4419 if (e->buffer_object)
4421 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
4422 e->buffer_object = 0;
4423 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
4425 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4426 vb->buffer_object = 0;
4429 if (e->data) e->data += e->stride * SrcStartIndex;
4433 return process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4434 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4438 * Get / Set Texture Stage States
4439 * TODO: Verify against dx9 definitions
4441 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4442 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4443 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4445 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4447 if (Stage >= MAX_TEXTURES) {
4448 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4452 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4453 This->updateStateBlock->textureState[Stage][Type] = Value;
4455 if (This->isRecordingState) {
4456 TRACE("Recording... not performing anything\n");
4460 /* Checked after the assignments to allow proper stateblock recording */
4461 if(oldValue == Value) {
4462 TRACE("App is setting the old value over, nothing to do\n");
4466 if(Stage > This->stateBlock->lowest_disabled_stage &&
4467 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4468 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4469 * Changes in other states are important on disabled stages too
4474 if(Type == WINED3DTSS_COLOROP) {
4477 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4478 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4479 * they have to be disabled
4481 * The current stage is dirtified below.
4483 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4484 TRACE("Additionally dirtifying stage %u\n", i);
4485 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4487 This->stateBlock->lowest_disabled_stage = Stage;
4488 TRACE("New lowest disabled: %u\n", Stage);
4489 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4490 /* Previously disabled stage enabled. Stages above it may need enabling
4491 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4492 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4494 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4497 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4498 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4501 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4502 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4504 This->stateBlock->lowest_disabled_stage = i;
4505 TRACE("New lowest disabled: %u\n", i);
4509 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4514 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4515 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4516 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4517 *pValue = This->updateStateBlock->textureState[Stage][Type];
4524 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4525 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4526 IWineD3DBaseTexture *oldTexture;
4528 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4530 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4531 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4534 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4535 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4536 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4539 oldTexture = This->updateStateBlock->textures[Stage];
4541 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4542 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
4544 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4545 return WINED3DERR_INVALIDCALL;
4548 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4549 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4551 This->updateStateBlock->changed.textures |= 1 << Stage;
4552 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4553 This->updateStateBlock->textures[Stage] = pTexture;
4555 /* Handle recording of state blocks */
4556 if (This->isRecordingState) {
4557 TRACE("Recording... not performing anything\n");
4561 if(oldTexture == pTexture) {
4562 TRACE("App is setting the same texture again, nothing to do\n");
4566 /** NOTE: MSDN says that setTexture increases the reference count,
4567 * and that the application must set the texture back to null (or have a leaky application),
4568 * This means we should pass the refcount up to the parent
4569 *******************************/
4570 if (NULL != This->updateStateBlock->textures[Stage]) {
4571 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4572 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4573 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4575 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4577 if (!oldTexture || dimensions != IWineD3DBaseTexture_GetTextureDimensions(oldTexture))
4579 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4582 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4583 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4584 * so the COLOROP and ALPHAOP have to be dirtified.
4586 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4587 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4589 if(bindCount == 1) {
4590 new->baseTexture.sampler = Stage;
4592 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4596 if (NULL != oldTexture) {
4597 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4598 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4600 IWineD3DBaseTexture_Release(oldTexture);
4601 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4602 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4603 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4606 if(bindCount && old->baseTexture.sampler == Stage) {
4608 /* Have to do a search for the other sampler(s) where the texture is bound to
4609 * Shouldn't happen as long as apps bind a texture only to one stage
4611 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4612 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4613 if(This->updateStateBlock->textures[i] == oldTexture) {
4614 old->baseTexture.sampler = i;
4621 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4626 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4627 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4629 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4631 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4632 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4635 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4636 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4637 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4640 *ppTexture=This->stateBlock->textures[Stage];
4642 IWineD3DBaseTexture_AddRef(*ppTexture);
4644 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4652 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4653 IWineD3DSurface **ppBackBuffer) {
4654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4655 IWineD3DSwapChain *swapChain;
4658 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4660 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4661 if (hr == WINED3D_OK) {
4662 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4663 IWineD3DSwapChain_Release(swapChain);
4665 *ppBackBuffer = NULL;
4670 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4671 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4672 WARN("(%p) : stub, calling idirect3d for now\n", This);
4673 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4676 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4678 IWineD3DSwapChain *swapChain;
4681 if(iSwapChain > 0) {
4682 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4683 if (hr == WINED3D_OK) {
4684 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4685 IWineD3DSwapChain_Release(swapChain);
4687 FIXME("(%p) Error getting display mode\n", This);
4690 /* Don't read the real display mode,
4691 but return the stored mode instead. X11 can't change the color
4692 depth, and some apps are pretty angry if they SetDisplayMode from
4693 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4695 Also don't relay to the swapchain because with ddraw it's possible
4696 that there isn't a swapchain at all */
4697 pMode->Width = This->ddraw_width;
4698 pMode->Height = This->ddraw_height;
4699 pMode->Format = This->ddraw_format;
4700 pMode->RefreshRate = 0;
4708 * Stateblock related functions
4711 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4712 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4713 IWineD3DStateBlock *stateblock;
4716 TRACE("(%p)\n", This);
4718 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4720 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4721 if (FAILED(hr)) return hr;
4723 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4724 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4725 This->isRecordingState = TRUE;
4727 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4732 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4733 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4735 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4737 if (!This->isRecordingState) {
4738 WARN("(%p) not recording! returning error\n", This);
4739 *ppStateBlock = NULL;
4740 return WINED3DERR_INVALIDCALL;
4743 for (i = 0; i <= WINEHIGHEST_RENDER_STATE >> 5; ++i)
4745 DWORD map = object->changed.renderState[i];
4746 for (j = 0; map; map >>= 1, ++j)
4748 if (!(map & 1)) continue;
4750 object->contained_render_states[object->num_contained_render_states++] = (i << 5) | j;
4754 for (i = 0; i <= HIGHEST_TRANSFORMSTATE >> 5; ++i)
4756 DWORD map = object->changed.transform[i];
4757 for (j = 0; map; map >>= 1, ++j)
4759 if (!(map & 1)) continue;
4761 object->contained_transform_states[object->num_contained_transform_states++] = (i << 5) | j;
4764 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4765 if(object->changed.vertexShaderConstantsF[i]) {
4766 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4767 object->num_contained_vs_consts_f++;
4770 for(i = 0; i < MAX_CONST_I; i++) {
4771 if (object->changed.vertexShaderConstantsI & (1 << i))
4773 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4774 object->num_contained_vs_consts_i++;
4777 for(i = 0; i < MAX_CONST_B; i++) {
4778 if (object->changed.vertexShaderConstantsB & (1 << i))
4780 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4781 object->num_contained_vs_consts_b++;
4784 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
4786 if (object->changed.pixelShaderConstantsF[i])
4788 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
4789 ++object->num_contained_ps_consts_f;
4792 for(i = 0; i < MAX_CONST_I; i++) {
4793 if (object->changed.pixelShaderConstantsI & (1 << i))
4795 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4796 object->num_contained_ps_consts_i++;
4799 for(i = 0; i < MAX_CONST_B; i++) {
4800 if (object->changed.pixelShaderConstantsB & (1 << i))
4802 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4803 object->num_contained_ps_consts_b++;
4806 for(i = 0; i < MAX_TEXTURES; i++) {
4807 DWORD map = object->changed.textureState[i];
4809 for(j = 0; map; map >>= 1, ++j)
4811 if (!(map & 1)) continue;
4813 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4814 object->contained_tss_states[object->num_contained_tss_states].state = j;
4815 ++object->num_contained_tss_states;
4818 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4819 DWORD map = object->changed.samplerState[i];
4821 for (j = 0; map; map >>= 1, ++j)
4823 if (!(map & 1)) continue;
4825 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4826 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4827 ++object->num_contained_sampler_states;
4831 *ppStateBlock = (IWineD3DStateBlock*) object;
4832 This->isRecordingState = FALSE;
4833 This->updateStateBlock = This->stateBlock;
4834 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4835 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4836 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4841 * Scene related functions
4843 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4844 /* At the moment we have no need for any functionality at the beginning
4846 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4847 TRACE("(%p)\n", This);
4850 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4851 return WINED3DERR_INVALIDCALL;
4853 This->inScene = TRUE;
4857 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4858 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4859 TRACE("(%p)\n", This);
4861 if(!This->inScene) {
4862 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4863 return WINED3DERR_INVALIDCALL;
4866 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
4867 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4869 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4873 This->inScene = FALSE;
4877 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4878 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4879 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4880 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4881 IWineD3DSwapChain *swapChain = NULL;
4883 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4885 TRACE("(%p) Presenting the frame\n", This);
4887 for(i = 0 ; i < swapchains ; i ++) {
4889 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4890 TRACE("presentinng chain %d, %p\n", i, swapChain);
4891 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4892 IWineD3DSwapChain_Release(swapChain);
4898 /* Not called from the VTable (internal subroutine) */
4899 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4900 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4901 float Z, DWORD Stencil) {
4902 GLbitfield glMask = 0;
4904 WINED3DRECT curRect;
4906 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4907 UINT drawable_width, drawable_height;
4908 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4909 IWineD3DSwapChainImpl *swapchain = NULL;
4911 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4912 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4913 * for the cleared parts, and the untouched parts.
4915 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4916 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4917 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4918 * checking all this if the dest surface is in the drawable anyway.
4920 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4922 if(vp->X != 0 || vp->Y != 0 ||
4923 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4924 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4927 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4928 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4929 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4930 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4931 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4934 if(Count > 0 && pRects && (
4935 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4936 pRects[0].x2 < target->currentDesc.Width ||
4937 pRects[0].y2 < target->currentDesc.Height)) {
4938 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4945 ActivateContext(This, (IWineD3DSurface *)target, CTXUSAGE_CLEAR);
4947 target->get_drawable_size(target, &drawable_width, &drawable_height);
4951 /* Only set the values up once, as they are not changing */
4952 if (Flags & WINED3DCLEAR_STENCIL) {
4953 glClearStencil(Stencil);
4954 checkGLcall("glClearStencil");
4955 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4956 glStencilMask(0xFFFFFFFF);
4959 if (Flags & WINED3DCLEAR_ZBUFFER) {
4960 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4961 glDepthMask(GL_TRUE);
4963 checkGLcall("glClearDepth");
4964 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4965 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4967 if (vp->X != 0 || vp->Y != 0 ||
4968 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4969 surface_load_ds_location(This->stencilBufferTarget, location);
4971 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4972 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4973 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4974 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4975 surface_load_ds_location(This->stencilBufferTarget, location);
4977 else if (Count > 0 && pRects && (
4978 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4979 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4980 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4981 surface_load_ds_location(This->stencilBufferTarget, location);
4985 if (Flags & WINED3DCLEAR_TARGET) {
4986 TRACE("Clearing screen with glClear to color %x\n", Color);
4987 glClearColor(D3DCOLOR_R(Color),
4991 checkGLcall("glClearColor");
4993 /* Clear ALL colors! */
4994 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4995 glMask = glMask | GL_COLOR_BUFFER_BIT;
4998 vp_rect.left = vp->X;
4999 vp_rect.top = vp->Y;
5000 vp_rect.right = vp->X + vp->Width;
5001 vp_rect.bottom = vp->Y + vp->Height;
5002 if (!(Count > 0 && pRects)) {
5003 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5004 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5006 if(This->render_offscreen) {
5007 glScissor(vp_rect.left, vp_rect.top,
5008 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5010 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5011 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5013 checkGLcall("glScissor");
5015 checkGLcall("glClear");
5017 /* Now process each rect in turn */
5018 for (i = 0; i < Count; i++) {
5019 /* Note gl uses lower left, width/height */
5020 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5021 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5022 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5024 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5025 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5026 curRect.x1, (target->currentDesc.Height - curRect.y2),
5027 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5029 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5030 * The rectangle is not cleared, no error is returned, but further rectanlges are
5031 * still cleared if they are valid
5033 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5034 TRACE("Rectangle with negative dimensions, ignoring\n");
5038 if(This->render_offscreen) {
5039 glScissor(curRect.x1, curRect.y1,
5040 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5042 glScissor(curRect.x1, drawable_height - curRect.y2,
5043 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5045 checkGLcall("glScissor");
5048 checkGLcall("glClear");
5052 /* Restore the old values (why..?) */
5053 if (Flags & WINED3DCLEAR_STENCIL) {
5054 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5056 if (Flags & WINED3DCLEAR_TARGET) {
5057 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5058 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5059 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5060 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5061 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5063 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5064 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5066 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
5068 if (Flags & WINED3DCLEAR_ZBUFFER) {
5069 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5070 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5071 surface_modify_ds_location(This->stencilBufferTarget, location);
5076 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5077 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5080 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5086 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5087 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5088 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5089 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5091 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5092 Count, pRects, Flags, Color, Z, Stencil);
5094 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5095 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5096 /* TODO: What about depth stencil buffers without stencil bits? */
5097 return WINED3DERR_INVALIDCALL;
5100 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5107 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
5108 WINED3DPRIMITIVETYPE primitive_type)
5110 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5112 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
5114 This->updateStateBlock->changed.primitive_type = TRUE;
5115 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
5118 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
5119 WINED3DPRIMITIVETYPE *primitive_type)
5121 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5123 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
5125 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
5127 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
5130 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
5132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5134 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
5136 if(!This->stateBlock->vertexDecl) {
5137 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5138 return WINED3DERR_INVALIDCALL;
5141 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5142 if(This->stateBlock->streamIsUP) {
5143 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5144 This->stateBlock->streamIsUP = FALSE;
5147 if(This->stateBlock->loadBaseVertexIndex != 0) {
5148 This->stateBlock->loadBaseVertexIndex = 0;
5149 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5151 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5152 drawPrimitive(iface, vertex_count, 0/* NumVertices */, StartVertex /* start_idx */,
5153 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5157 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5158 UINT minIndex, UINT NumVertices, UINT startIndex, UINT index_count)
5160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5162 IWineD3DBuffer *pIB;
5165 pIB = This->stateBlock->pIndexData;
5167 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5168 * without an index buffer set. (The first time at least...)
5169 * D3D8 simply dies, but I doubt it can do much harm to return
5170 * D3DERR_INVALIDCALL there as well. */
5171 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5172 return WINED3DERR_INVALIDCALL;
5175 if(!This->stateBlock->vertexDecl) {
5176 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5177 return WINED3DERR_INVALIDCALL;
5180 if(This->stateBlock->streamIsUP) {
5181 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5182 This->stateBlock->streamIsUP = FALSE;
5184 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
5186 TRACE("(%p) : min %u, vertex count %u, startIdx %u, index count %u\n",
5187 This, minIndex, NumVertices, startIndex, index_count);
5189 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
5195 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5196 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5197 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5200 drawPrimitive(iface, index_count, NumVertices, startIndex, idxStride,
5201 vbo ? NULL : ((struct wined3d_buffer *) pIB)->resource.allocatedMemory, minIndex);
5206 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
5207 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5212 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
5213 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
5215 if(!This->stateBlock->vertexDecl) {
5216 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5217 return WINED3DERR_INVALIDCALL;
5220 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5221 vb = This->stateBlock->streamSource[0];
5222 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5223 if (vb) IWineD3DBuffer_Release(vb);
5224 This->stateBlock->streamOffset[0] = 0;
5225 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5226 This->stateBlock->streamIsUP = TRUE;
5227 This->stateBlock->loadBaseVertexIndex = 0;
5229 /* TODO: Only mark dirty if drawing from a different UP address */
5230 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5232 drawPrimitive(iface, vertex_count, 0 /* NumVertices */, 0 /* start_idx */,
5233 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5235 /* MSDN specifies stream zero settings must be set to NULL */
5236 This->stateBlock->streamStride[0] = 0;
5237 This->stateBlock->streamSource[0] = NULL;
5239 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5240 * the new stream sources or use UP drawing again
5245 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, UINT MinVertexIndex,
5246 UINT NumVertices, UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
5247 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5254 TRACE("(%p) : MinVtxIdx %u, NumVIdx %u, index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u\n",
5255 This, MinVertexIndex, NumVertices, index_count, pIndexData,
5256 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5258 if(!This->stateBlock->vertexDecl) {
5259 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5260 return WINED3DERR_INVALIDCALL;
5263 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
5269 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5270 vb = This->stateBlock->streamSource[0];
5271 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5272 if (vb) IWineD3DBuffer_Release(vb);
5273 This->stateBlock->streamIsUP = TRUE;
5274 This->stateBlock->streamOffset[0] = 0;
5275 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5277 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5278 This->stateBlock->baseVertexIndex = 0;
5279 This->stateBlock->loadBaseVertexIndex = 0;
5280 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5281 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5282 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5284 drawPrimitive(iface, index_count, NumVertices, 0 /* start_idx */,
5285 idxStride, pIndexData, MinVertexIndex);
5287 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5288 This->stateBlock->streamSource[0] = NULL;
5289 This->stateBlock->streamStride[0] = 0;
5290 ib = This->stateBlock->pIndexData;
5292 IWineD3DBuffer_Release(ib);
5293 This->stateBlock->pIndexData = NULL;
5295 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5296 * SetStreamSource to specify a vertex buffer
5302 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5303 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
5305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5307 /* Mark the state dirty until we have nicer tracking
5308 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5311 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5312 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5313 This->stateBlock->baseVertexIndex = 0;
5314 This->up_strided = DrawPrimStrideData;
5315 drawPrimitive(iface, vertex_count, 0, 0, 0, NULL, 0);
5316 This->up_strided = NULL;
5320 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5321 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
5322 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
5324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5325 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5327 /* Mark the state dirty until we have nicer tracking
5328 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5331 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5332 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5333 This->stateBlock->streamIsUP = TRUE;
5334 This->stateBlock->baseVertexIndex = 0;
5335 This->up_strided = DrawPrimStrideData;
5336 drawPrimitive(iface, vertex_count, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData, 0 /* minindex */);
5337 This->up_strided = NULL;
5341 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5342 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5343 * not callable by the app directly no parameter validation checks are needed here.
5345 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5346 WINED3DLOCKED_BOX src;
5347 WINED3DLOCKED_BOX dst;
5349 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5351 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5352 * dirtification to improve loading performance.
5354 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5355 if(FAILED(hr)) return hr;
5356 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5358 IWineD3DVolume_UnlockBox(pSourceVolume);
5362 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5364 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5366 IWineD3DVolume_UnlockBox(pSourceVolume);
5368 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5373 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5374 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5375 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5376 HRESULT hr = WINED3D_OK;
5377 WINED3DRESOURCETYPE sourceType;
5378 WINED3DRESOURCETYPE destinationType;
5381 /* TODO: think about moving the code into IWineD3DBaseTexture */
5383 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5385 /* verify that the source and destination textures aren't NULL */
5386 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5387 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5388 This, pSourceTexture, pDestinationTexture);
5389 hr = WINED3DERR_INVALIDCALL;
5392 if (pSourceTexture == pDestinationTexture) {
5393 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5394 This, pSourceTexture, pDestinationTexture);
5395 hr = WINED3DERR_INVALIDCALL;
5397 /* Verify that the source and destination textures are the same type */
5398 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5399 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5401 if (sourceType != destinationType) {
5402 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5404 hr = WINED3DERR_INVALIDCALL;
5407 /* check that both textures have the identical numbers of levels */
5408 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5409 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5410 hr = WINED3DERR_INVALIDCALL;
5413 if (WINED3D_OK == hr) {
5414 IWineD3DBaseTextureImpl *pDestImpl = (IWineD3DBaseTextureImpl *) pDestinationTexture;
5416 /* Make sure that the destination texture is loaded */
5417 pDestImpl->baseTexture.internal_preload(pDestinationTexture, SRGB_RGB);
5419 /* Update every surface level of the texture */
5420 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5422 switch (sourceType) {
5423 case WINED3DRTYPE_TEXTURE:
5425 IWineD3DSurface *srcSurface;
5426 IWineD3DSurface *destSurface;
5428 for (i = 0 ; i < levels ; ++i) {
5429 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5430 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5431 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5432 IWineD3DSurface_Release(srcSurface);
5433 IWineD3DSurface_Release(destSurface);
5434 if (WINED3D_OK != hr) {
5435 WARN("(%p) : Call to update surface failed\n", This);
5441 case WINED3DRTYPE_CUBETEXTURE:
5443 IWineD3DSurface *srcSurface;
5444 IWineD3DSurface *destSurface;
5445 WINED3DCUBEMAP_FACES faceType;
5447 for (i = 0 ; i < levels ; ++i) {
5448 /* Update each cube face */
5449 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5450 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5451 if (WINED3D_OK != hr) {
5452 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5454 TRACE("Got srcSurface %p\n", srcSurface);
5456 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5457 if (WINED3D_OK != hr) {
5458 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5460 TRACE("Got desrSurface %p\n", destSurface);
5462 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5463 IWineD3DSurface_Release(srcSurface);
5464 IWineD3DSurface_Release(destSurface);
5465 if (WINED3D_OK != hr) {
5466 WARN("(%p) : Call to update surface failed\n", This);
5474 case WINED3DRTYPE_VOLUMETEXTURE:
5476 IWineD3DVolume *srcVolume = NULL;
5477 IWineD3DVolume *destVolume = NULL;
5479 for (i = 0 ; i < levels ; ++i) {
5480 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5481 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5482 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5483 IWineD3DVolume_Release(srcVolume);
5484 IWineD3DVolume_Release(destVolume);
5485 if (WINED3D_OK != hr) {
5486 WARN("(%p) : Call to update volume failed\n", This);
5494 FIXME("(%p) : Unsupported source and destination type\n", This);
5495 hr = WINED3DERR_INVALIDCALL;
5502 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5503 IWineD3DSwapChain *swapChain;
5505 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5506 if(hr == WINED3D_OK) {
5507 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5508 IWineD3DSwapChain_Release(swapChain);
5513 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5514 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5515 IWineD3DBaseTextureImpl *texture;
5518 TRACE("(%p) : %p\n", This, pNumPasses);
5520 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5521 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5522 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5523 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5525 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5526 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5527 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5530 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5531 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5533 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5534 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5537 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5538 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5541 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5542 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5543 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5548 /* return a sensible default */
5551 TRACE("returning D3D_OK\n");
5555 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5559 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5560 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5561 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8
5562 || texture->resource.format_desc->format == WINED3DFMT_A8P8))
5564 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5569 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5570 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5573 PALETTEENTRY **palettes;
5575 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5577 if (PaletteNumber >= MAX_PALETTES) {
5578 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5579 return WINED3DERR_INVALIDCALL;
5582 if (PaletteNumber >= This->NumberOfPalettes) {
5583 NewSize = This->NumberOfPalettes;
5586 } while(PaletteNumber >= NewSize);
5587 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5589 ERR("Out of memory!\n");
5590 return E_OUTOFMEMORY;
5592 This->palettes = palettes;
5593 This->NumberOfPalettes = NewSize;
5596 if (!This->palettes[PaletteNumber]) {
5597 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5598 if (!This->palettes[PaletteNumber]) {
5599 ERR("Out of memory!\n");
5600 return E_OUTOFMEMORY;
5604 for (j = 0; j < 256; ++j) {
5605 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5606 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5607 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5608 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5610 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5611 TRACE("(%p) : returning\n", This);
5615 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5616 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5618 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5619 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5620 /* What happens in such situation isn't documented; Native seems to silently abort
5621 on such conditions. Return Invalid Call. */
5622 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5623 return WINED3DERR_INVALIDCALL;
5625 for (j = 0; j < 256; ++j) {
5626 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5627 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5628 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5629 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5631 TRACE("(%p) : returning\n", This);
5635 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5636 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5637 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5638 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5639 (tested with reference rasterizer). Return Invalid Call. */
5640 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5641 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5642 return WINED3DERR_INVALIDCALL;
5644 /*TODO: stateblocks */
5645 if (This->currentPalette != PaletteNumber) {
5646 This->currentPalette = PaletteNumber;
5647 dirtify_p8_texture_samplers(This);
5649 TRACE("(%p) : returning\n", This);
5653 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5655 if (PaletteNumber == NULL) {
5656 WARN("(%p) : returning Invalid Call\n", This);
5657 return WINED3DERR_INVALIDCALL;
5659 /*TODO: stateblocks */
5660 *PaletteNumber = This->currentPalette;
5661 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5665 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5666 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5670 FIXME("(%p) : stub\n", This);
5674 This->softwareVertexProcessing = bSoftware;
5679 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5684 FIXME("(%p) : stub\n", This);
5687 return This->softwareVertexProcessing;
5691 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5692 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5693 IWineD3DSwapChain *swapChain;
5696 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5698 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5699 if(hr == WINED3D_OK){
5700 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5701 IWineD3DSwapChain_Release(swapChain);
5703 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5709 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5710 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5712 if(nSegments != 0.0f) {
5715 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5722 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5723 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5727 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5733 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5734 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5735 /** TODO: remove casts to IWineD3DSurfaceImpl
5736 * NOTE: move code to surface to accomplish this
5737 ****************************************/
5738 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5739 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)pDestinationSurface;
5740 int srcWidth, srcHeight;
5741 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5742 WINED3DFORMAT destFormat, srcFormat;
5744 int srcLeft, destLeft, destTop;
5745 WINED3DPOOL srcPool, destPool;
5747 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5748 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
5752 CONVERT_TYPES convert = NO_CONVERSION;
5754 WINED3DSURFACE_DESC winedesc;
5756 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5758 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5759 srcSurfaceWidth = winedesc.width;
5760 srcSurfaceHeight = winedesc.height;
5761 srcPool = winedesc.pool;
5762 srcFormat = winedesc.format;
5764 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5765 destSurfaceWidth = winedesc.width;
5766 destSurfaceHeight = winedesc.height;
5767 destPool = winedesc.pool;
5768 destFormat = winedesc.format;
5769 destSize = winedesc.size;
5771 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5772 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5773 return WINED3DERR_INVALIDCALL;
5776 /* This call loads the opengl surface directly, instead of copying the surface to the
5777 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5778 * copy in sysmem and use regular surface loading.
5780 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5781 if(convert != NO_CONVERSION) {
5782 return IWineD3DSurface_BltFast(pDestinationSurface,
5783 pDestPoint ? pDestPoint->x : 0,
5784 pDestPoint ? pDestPoint->y : 0,
5785 pSourceSurface, pSourceRect, 0);
5788 if (destFormat == WINED3DFMT_UNKNOWN) {
5789 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5790 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5792 /* Get the update surface description */
5793 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5796 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
5799 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5800 checkGLcall("glActiveTextureARB");
5803 /* Make sure the surface is loaded and up to date */
5804 surface_internal_preload(pDestinationSurface, SRGB_RGB);
5805 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5807 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
5808 dst_format_desc = dst_impl->resource.format_desc;
5810 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5811 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5812 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5813 srcLeft = pSourceRect ? pSourceRect->left : 0;
5814 destLeft = pDestPoint ? pDestPoint->x : 0;
5815 destTop = pDestPoint ? pDestPoint->y : 0;
5818 /* This function doesn't support compressed textures
5819 the pitch is just bytesPerPixel * width */
5820 if(srcWidth != srcSurfaceWidth || srcLeft ){
5821 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
5822 offset += srcLeft * src_format_desc->byte_count;
5823 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5825 /* TODO DXT formats */
5827 if(pSourceRect != NULL && pSourceRect->top != 0){
5828 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
5830 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5831 This, dst_impl->texture_level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
5832 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5835 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5837 /* need to lock the surface to get the data */
5838 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5843 /* TODO: Cube and volume support */
5845 /* not a whole row so we have to do it a line at a time */
5848 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5849 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5851 for (j = destTop; j < (srcHeight + destTop); ++j)
5853 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, j,
5854 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
5858 } else { /* Full width, so just write out the whole texture */
5859 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5861 if (dst_format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
5863 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth)
5865 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across. */
5866 FIXME("Updating part of a compressed texture is not supported.\n");
5868 if (destFormat != srcFormat)
5870 FIXME("Updating mixed format compressed textures is not supported.\n");
5874 GL_EXTCALL(glCompressedTexImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5875 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
5880 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, destTop,
5881 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
5884 checkGLcall("glTexSubImage2D");
5888 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5889 sampler = This->rev_tex_unit_map[0];
5890 if (sampler != -1) {
5891 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5897 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5898 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5899 struct WineD3DRectPatch *patch;
5900 GLenum old_primitive_type;
5904 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5906 if(!(Handle || pRectPatchInfo)) {
5907 /* TODO: Write a test for the return value, thus the FIXME */
5908 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5909 return WINED3DERR_INVALIDCALL;
5913 i = PATCHMAP_HASHFUNC(Handle);
5915 LIST_FOR_EACH(e, &This->patches[i]) {
5916 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5917 if(patch->Handle == Handle) {
5924 TRACE("Patch does not exist. Creating a new one\n");
5925 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5926 patch->Handle = Handle;
5927 list_add_head(&This->patches[i], &patch->entry);
5929 TRACE("Found existing patch %p\n", patch);
5932 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5933 * attributes we have to tesselate, read back, and draw. This needs a patch
5934 * management structure instance. Create one.
5936 * A possible improvement is to check if a vertex shader is used, and if not directly
5939 FIXME("Drawing an uncached patch. This is slow\n");
5940 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5943 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5944 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5945 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5947 TRACE("Tesselation density or patch info changed, retesselating\n");
5949 if(pRectPatchInfo) {
5950 patch->RectPatchInfo = *pRectPatchInfo;
5952 patch->numSegs[0] = pNumSegs[0];
5953 patch->numSegs[1] = pNumSegs[1];
5954 patch->numSegs[2] = pNumSegs[2];
5955 patch->numSegs[3] = pNumSegs[3];
5957 hr = tesselate_rectpatch(This, patch);
5959 WARN("Patch tesselation failed\n");
5961 /* Do not release the handle to store the params of the patch */
5963 HeapFree(GetProcessHeap(), 0, patch);
5969 This->currentPatch = patch;
5970 old_primitive_type = This->stateBlock->gl_primitive_type;
5971 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5972 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5973 This->stateBlock->gl_primitive_type = old_primitive_type;
5974 This->currentPatch = NULL;
5976 /* Destroy uncached patches */
5978 HeapFree(GetProcessHeap(), 0, patch->mem);
5979 HeapFree(GetProcessHeap(), 0, patch);
5984 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5985 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5986 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5987 FIXME("(%p) : Stub\n", This);
5991 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5992 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5994 struct WineD3DRectPatch *patch;
5996 TRACE("(%p) Handle(%d)\n", This, Handle);
5998 i = PATCHMAP_HASHFUNC(Handle);
5999 LIST_FOR_EACH(e, &This->patches[i]) {
6000 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6001 if(patch->Handle == Handle) {
6002 TRACE("Deleting patch %p\n", patch);
6003 list_remove(&patch->entry);
6004 HeapFree(GetProcessHeap(), 0, patch->mem);
6005 HeapFree(GetProcessHeap(), 0, patch);
6010 /* TODO: Write a test for the return value */
6011 FIXME("Attempt to destroy nonexistent patch\n");
6012 return WINED3DERR_INVALIDCALL;
6015 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6017 IWineD3DSwapChain *swapchain;
6019 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6020 if (SUCCEEDED(hr)) {
6021 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6028 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
6029 const WINED3DRECT *rect, const float color[4])
6031 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6032 IWineD3DSwapChain *swapchain;
6034 swapchain = get_swapchain(surface);
6038 TRACE("Surface %p is onscreen\n", surface);
6040 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6042 context_bind_fbo(This->activeContext, GL_FRAMEBUFFER_EXT, NULL);
6043 buffer = surface_get_gl_buffer(surface, swapchain);
6044 glDrawBuffer(buffer);
6045 checkGLcall("glDrawBuffer()");
6047 TRACE("Surface %p is offscreen\n", surface);
6049 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6051 context_bind_fbo(This->activeContext, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6052 context_attach_surface_fbo(This->activeContext, GL_FRAMEBUFFER_EXT, 0, surface);
6053 context_attach_depth_stencil_fbo(This->activeContext, GL_FRAMEBUFFER_EXT, NULL, FALSE);
6057 glEnable(GL_SCISSOR_TEST);
6059 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6061 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6062 rect->x2 - rect->x1, rect->y2 - rect->y1);
6064 checkGLcall("glScissor");
6065 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6067 glDisable(GL_SCISSOR_TEST);
6069 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6071 glDisable(GL_BLEND);
6072 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6074 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6075 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6077 glClearColor(color[0], color[1], color[2], color[3]);
6078 glClear(GL_COLOR_BUFFER_BIT);
6079 checkGLcall("glClear");
6081 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6082 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6083 glDrawBuffer(GL_BACK);
6084 checkGLcall("glDrawBuffer()");
6090 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6091 unsigned int r, g, b, a;
6094 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6095 destfmt == WINED3DFMT_R8G8B8)
6098 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6100 a = (color & 0xff000000) >> 24;
6101 r = (color & 0x00ff0000) >> 16;
6102 g = (color & 0x0000ff00) >> 8;
6103 b = (color & 0x000000ff) >> 0;
6107 case WINED3DFMT_R5G6B5:
6108 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6115 TRACE("Returning %08x\n", ret);
6118 case WINED3DFMT_X1R5G5B5:
6119 case WINED3DFMT_A1R5G5B5:
6128 TRACE("Returning %08x\n", ret);
6131 case WINED3DFMT_A8_UNORM:
6132 TRACE("Returning %08x\n", a);
6135 case WINED3DFMT_X4R4G4B4:
6136 case WINED3DFMT_A4R4G4B4:
6145 TRACE("Returning %08x\n", ret);
6148 case WINED3DFMT_R3G3B2:
6155 TRACE("Returning %08x\n", ret);
6158 case WINED3DFMT_X8B8G8R8:
6159 case WINED3DFMT_R8G8B8A8_UNORM:
6164 TRACE("Returning %08x\n", ret);
6167 case WINED3DFMT_A2R10G10B10:
6169 r = (r * 1024) / 256;
6170 g = (g * 1024) / 256;
6171 b = (b * 1024) / 256;
6176 TRACE("Returning %08x\n", ret);
6179 case WINED3DFMT_R10G10B10A2_UNORM:
6181 r = (r * 1024) / 256;
6182 g = (g * 1024) / 256;
6183 b = (b * 1024) / 256;
6188 TRACE("Returning %08x\n", ret);
6192 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6197 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6198 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6199 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6201 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6203 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6204 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6205 return WINED3DERR_INVALIDCALL;
6208 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6209 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
6210 color_fill_fbo(iface, pSurface, pRect, c);
6213 /* Just forward this to the DirectDraw blitting engine */
6214 memset(&BltFx, 0, sizeof(BltFx));
6215 BltFx.dwSize = sizeof(BltFx);
6216 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
6217 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6218 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6222 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
6223 IWineD3DRendertargetView *rendertarget_view, const float color[4])
6225 IWineD3DResource *resource;
6226 IWineD3DSurface *surface;
6229 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
6232 ERR("Failed to get resource, hr %#x\n", hr);
6236 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
6238 FIXME("Only supported on surface resources\n");
6239 IWineD3DResource_Release(resource);
6243 surface = (IWineD3DSurface *)resource;
6245 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6247 color_fill_fbo(iface, surface, NULL, color);
6254 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
6256 c = ((DWORD)(color[2] * 255.0f));
6257 c |= ((DWORD)(color[1] * 255.0f)) << 8;
6258 c |= ((DWORD)(color[0] * 255.0f)) << 16;
6259 c |= ((DWORD)(color[3] * 255.0f)) << 24;
6261 /* Just forward this to the DirectDraw blitting engine */
6262 memset(&BltFx, 0, sizeof(BltFx));
6263 BltFx.dwSize = sizeof(BltFx);
6264 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
6265 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6268 ERR("Blt failed, hr %#x\n", hr);
6272 IWineD3DResource_Release(resource);
6275 /* rendertarget and depth stencil functions */
6276 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6277 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6279 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6280 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6281 return WINED3DERR_INVALIDCALL;
6284 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6285 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6286 /* Note inc ref on returned surface */
6287 if(*ppRenderTarget != NULL)
6288 IWineD3DSurface_AddRef(*ppRenderTarget);
6292 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6294 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6295 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6296 IWineD3DSwapChainImpl *Swapchain;
6299 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6301 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6302 if(hr != WINED3D_OK) {
6303 ERR("Can't get the swapchain\n");
6307 /* Make sure to release the swapchain */
6308 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6310 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6311 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6312 return WINED3DERR_INVALIDCALL;
6314 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6315 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6316 return WINED3DERR_INVALIDCALL;
6319 if(Swapchain->frontBuffer != Front) {
6320 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6322 if(Swapchain->frontBuffer)
6324 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6325 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
6327 Swapchain->frontBuffer = Front;
6329 if(Swapchain->frontBuffer) {
6330 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6331 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
6335 if(Back && !Swapchain->backBuffer) {
6336 /* We need memory for the back buffer array - only one back buffer this way */
6337 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6338 if(!Swapchain->backBuffer) {
6339 ERR("Out of memory\n");
6340 return E_OUTOFMEMORY;
6344 if(Swapchain->backBuffer[0] != Back) {
6345 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6347 /* What to do about the context here in the case of multithreading? Not sure.
6348 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6350 WARN("No active context?\n");
6353 if(!Swapchain->backBuffer[0]) {
6354 /* GL was told to draw to the front buffer at creation,
6357 glDrawBuffer(GL_BACK);
6358 checkGLcall("glDrawBuffer(GL_BACK)");
6359 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6360 Swapchain->presentParms.BackBufferCount = 1;
6362 /* That makes problems - disable for now */
6363 /* glDrawBuffer(GL_FRONT); */
6364 checkGLcall("glDrawBuffer(GL_FRONT)");
6365 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6366 Swapchain->presentParms.BackBufferCount = 0;
6370 if(Swapchain->backBuffer[0])
6372 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6373 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
6375 Swapchain->backBuffer[0] = Back;
6377 if(Swapchain->backBuffer[0]) {
6378 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6379 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
6381 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6382 Swapchain->backBuffer = NULL;
6390 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6391 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6392 *ppZStencilSurface = This->stencilBufferTarget;
6393 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6395 if(*ppZStencilSurface != NULL) {
6396 /* Note inc ref on returned surface */
6397 IWineD3DSurface_AddRef(*ppZStencilSurface);
6400 return WINED3DERR_NOTFOUND;
6404 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6405 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6407 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6408 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6409 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6411 POINT offset = {0, 0};
6413 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6414 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6415 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6416 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6419 case WINED3DTEXF_LINEAR:
6420 gl_filter = GL_LINEAR;
6424 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6425 case WINED3DTEXF_NONE:
6426 case WINED3DTEXF_POINT:
6427 gl_filter = GL_NEAREST;
6431 /* Attach src surface to src fbo */
6432 src_swapchain = get_swapchain(src_surface);
6433 dst_swapchain = get_swapchain(dst_surface);
6435 if (src_swapchain) ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6436 else if (dst_swapchain) ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6437 else ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6439 if (src_swapchain) {
6440 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6442 TRACE("Source surface %p is onscreen\n", src_surface);
6443 /* Make sure the drawable is up to date. In the offscreen case
6444 * attach_surface_fbo() implicitly takes care of this. */
6445 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6447 if(buffer == GL_FRONT) {
6450 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6451 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6452 h = windowsize.bottom - windowsize.top;
6453 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6454 src_rect->y1 = offset.y + h - src_rect->y1;
6455 src_rect->y2 = offset.y + h - src_rect->y2;
6457 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6458 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6462 context_bind_fbo(This->activeContext, GL_READ_FRAMEBUFFER_EXT, NULL);
6463 glReadBuffer(buffer);
6464 checkGLcall("glReadBuffer()");
6466 TRACE("Source surface %p is offscreen\n", src_surface);
6468 context_bind_fbo(This->activeContext, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6469 context_attach_surface_fbo(This->activeContext, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6470 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6471 checkGLcall("glReadBuffer()");
6472 context_attach_depth_stencil_fbo(This->activeContext, GL_READ_FRAMEBUFFER_EXT, NULL, FALSE);
6476 /* Attach dst surface to dst fbo */
6477 if (dst_swapchain) {
6478 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6480 TRACE("Destination surface %p is onscreen\n", dst_surface);
6481 /* Make sure the drawable is up to date. In the offscreen case
6482 * attach_surface_fbo() implicitly takes care of this. */
6483 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6485 if(buffer == GL_FRONT) {
6488 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6489 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6490 h = windowsize.bottom - windowsize.top;
6491 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6492 dst_rect->y1 = offset.y + h - dst_rect->y1;
6493 dst_rect->y2 = offset.y + h - dst_rect->y2;
6495 /* Screen coords = window coords, surface height = window height */
6496 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6497 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6501 context_bind_fbo(This->activeContext, GL_DRAW_FRAMEBUFFER_EXT, NULL);
6502 glDrawBuffer(buffer);
6503 checkGLcall("glDrawBuffer()");
6505 TRACE("Destination surface %p is offscreen\n", dst_surface);
6508 context_bind_fbo(This->activeContext, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6509 context_attach_surface_fbo(This->activeContext, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6510 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6511 checkGLcall("glDrawBuffer()");
6512 context_attach_depth_stencil_fbo(This->activeContext, GL_DRAW_FRAMEBUFFER_EXT, NULL, FALSE);
6514 glDisable(GL_SCISSOR_TEST);
6515 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6518 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6519 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6520 checkGLcall("glBlitFramebuffer()");
6522 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6523 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6524 checkGLcall("glBlitFramebuffer()");
6527 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6529 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6530 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6531 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6532 glDrawBuffer(GL_BACK);
6533 checkGLcall("glDrawBuffer()");
6538 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6540 WINED3DVIEWPORT viewport;
6542 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6544 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6545 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6546 This, RenderTargetIndex, GL_LIMITS(buffers));
6547 return WINED3DERR_INVALIDCALL;
6550 /* MSDN says that null disables the render target
6551 but a device must always be associated with a render target
6552 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6554 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6555 FIXME("Trying to set render target 0 to NULL\n");
6556 return WINED3DERR_INVALIDCALL;
6558 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6559 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);
6560 return WINED3DERR_INVALIDCALL;
6563 /* If we are trying to set what we already have, don't bother */
6564 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6565 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6568 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6569 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6570 This->render_targets[RenderTargetIndex] = pRenderTarget;
6572 /* Render target 0 is special */
6573 if(RenderTargetIndex == 0) {
6574 /* Finally, reset the viewport as the MSDN states. */
6575 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6576 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6579 viewport.MaxZ = 1.0f;
6580 viewport.MinZ = 0.0f;
6581 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6582 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6583 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6585 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6590 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6591 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6592 HRESULT hr = WINED3D_OK;
6593 IWineD3DSurface *tmp;
6595 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6597 if (pNewZStencil == This->stencilBufferTarget) {
6598 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6600 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6601 * depending on the renter target implementation being used.
6602 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6603 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6604 * stencil buffer and incur an extra memory overhead
6605 ******************************************************/
6607 if (This->stencilBufferTarget) {
6608 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6609 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6610 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6612 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6613 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6614 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6618 tmp = This->stencilBufferTarget;
6619 This->stencilBufferTarget = pNewZStencil;
6620 /* should we be calling the parent or the wined3d surface? */
6621 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6622 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6625 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6626 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6627 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6628 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6629 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6636 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6637 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6638 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6639 /* TODO: the use of Impl is deprecated. */
6640 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6641 WINED3DLOCKED_RECT lockedRect;
6643 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6645 /* some basic validation checks */
6646 if(This->cursorTexture) {
6647 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6649 glDeleteTextures(1, &This->cursorTexture);
6651 This->cursorTexture = 0;
6654 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6655 This->haveHardwareCursor = TRUE;
6657 This->haveHardwareCursor = FALSE;
6660 WINED3DLOCKED_RECT rect;
6662 /* MSDN: Cursor must be A8R8G8B8 */
6663 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format_desc->format)
6665 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6666 return WINED3DERR_INVALIDCALL;
6669 /* MSDN: Cursor must be smaller than the display mode */
6670 if(pSur->currentDesc.Width > This->ddraw_width ||
6671 pSur->currentDesc.Height > This->ddraw_height) {
6672 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);
6673 return WINED3DERR_INVALIDCALL;
6676 if (!This->haveHardwareCursor) {
6677 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6679 /* Do not store the surface's pointer because the application may
6680 * release it after setting the cursor image. Windows doesn't
6681 * addref the set surface, so we can't do this either without
6682 * creating circular refcount dependencies. Copy out the gl texture
6685 This->cursorWidth = pSur->currentDesc.Width;
6686 This->cursorHeight = pSur->currentDesc.Height;
6687 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6689 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION);
6690 char *mem, *bits = rect.pBits;
6691 GLint intfmt = glDesc->glInternal;
6692 GLint format = glDesc->glFormat;
6693 GLint type = glDesc->glType;
6694 INT height = This->cursorHeight;
6695 INT width = This->cursorWidth;
6696 INT bpp = glDesc->byte_count;
6699 /* Reformat the texture memory (pitch and width can be
6701 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6702 for(i = 0; i < height; i++)
6703 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6704 IWineD3DSurface_UnlockRect(pCursorBitmap);
6706 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6710 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6711 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6712 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6715 /* Make sure that a proper texture unit is selected */
6716 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6717 checkGLcall("glActiveTextureARB");
6718 sampler = This->rev_tex_unit_map[0];
6719 if (sampler != -1) {
6720 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6722 /* Create a new cursor texture */
6723 glGenTextures(1, &This->cursorTexture);
6724 checkGLcall("glGenTextures");
6725 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6726 checkGLcall("glBindTexture");
6727 /* Copy the bitmap memory into the cursor texture */
6728 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6729 HeapFree(GetProcessHeap(), 0, mem);
6730 checkGLcall("glTexImage2D");
6732 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6733 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6734 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6741 FIXME("A cursor texture was not returned.\n");
6742 This->cursorTexture = 0;
6747 /* Draw a hardware cursor */
6748 ICONINFO cursorInfo;
6750 /* Create and clear maskBits because it is not needed for
6751 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6753 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6754 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6755 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6756 WINED3DLOCK_NO_DIRTY_UPDATE |
6757 WINED3DLOCK_READONLY
6759 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6760 pSur->currentDesc.Height);
6762 cursorInfo.fIcon = FALSE;
6763 cursorInfo.xHotspot = XHotSpot;
6764 cursorInfo.yHotspot = YHotSpot;
6765 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6766 pSur->currentDesc.Height, 1,
6768 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6769 pSur->currentDesc.Height, 1,
6770 32, lockedRect.pBits);
6771 IWineD3DSurface_UnlockRect(pCursorBitmap);
6772 /* Create our cursor and clean up. */
6773 cursor = CreateIconIndirect(&cursorInfo);
6775 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6776 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6777 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6778 This->hardwareCursor = cursor;
6779 HeapFree(GetProcessHeap(), 0, maskBits);
6783 This->xHotSpot = XHotSpot;
6784 This->yHotSpot = YHotSpot;
6788 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6789 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6790 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6792 This->xScreenSpace = XScreenSpace;
6793 This->yScreenSpace = YScreenSpace;
6799 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6800 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6801 BOOL oldVisible = This->bCursorVisible;
6804 TRACE("(%p) : visible(%d)\n", This, bShow);
6807 * When ShowCursor is first called it should make the cursor appear at the OS's last
6808 * known cursor position. Because of this, some applications just repetitively call
6809 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6812 This->xScreenSpace = pt.x;
6813 This->yScreenSpace = pt.y;
6815 if (This->haveHardwareCursor) {
6816 This->bCursorVisible = bShow;
6818 SetCursor(This->hardwareCursor);
6824 if (This->cursorTexture)
6825 This->bCursorVisible = bShow;
6831 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6832 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6833 IWineD3DResourceImpl *resource;
6834 TRACE("(%p) : state (%u)\n", This, This->state);
6836 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6837 switch (This->state) {
6840 case WINED3DERR_DEVICELOST:
6842 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6843 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6844 return WINED3DERR_DEVICENOTRESET;
6846 return WINED3DERR_DEVICELOST;
6848 case WINED3DERR_DRIVERINTERNALERROR:
6849 return WINED3DERR_DRIVERINTERNALERROR;
6853 return WINED3DERR_DRIVERINTERNALERROR;
6856 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6857 TRACE("checking resource %p for eviction\n", resource);
6858 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6859 TRACE("Evicting %p\n", resource);
6860 IWineD3DResource_UnLoad(resource);
6862 IWineD3DResource_Release(resource);
6866 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6867 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6868 TRACE("(%p)\n", This);
6870 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6874 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6876 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6878 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6879 if(surface->Flags & SFLAG_DIBSECTION) {
6880 /* Release the DC */
6881 SelectObject(surface->hDC, surface->dib.holdbitmap);
6882 DeleteDC(surface->hDC);
6883 /* Release the DIB section */
6884 DeleteObject(surface->dib.DIBsection);
6885 surface->dib.bitmap_data = NULL;
6886 surface->resource.allocatedMemory = NULL;
6887 surface->Flags &= ~SFLAG_DIBSECTION;
6889 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6890 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6891 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
6892 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
6893 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6894 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6896 surface->pow2Width = surface->pow2Height = 1;
6897 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6898 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6900 surface->glRect.left = 0;
6901 surface->glRect.top = 0;
6902 surface->glRect.right = surface->pow2Width;
6903 surface->glRect.bottom = surface->pow2Height;
6905 if (surface->texture_name)
6907 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6909 glDeleteTextures(1, &surface->texture_name);
6911 surface->texture_name = 0;
6912 surface->Flags &= ~SFLAG_CLIENT;
6914 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6915 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6916 surface->Flags |= SFLAG_NONPOW2;
6918 surface->Flags &= ~SFLAG_NONPOW2;
6920 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6921 surface->resource.allocatedMemory = NULL;
6922 surface->resource.heapMemory = NULL;
6923 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6924 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
6925 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
6926 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
6928 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
6932 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6933 TRACE("Unloading resource %p\n", resource);
6934 IWineD3DResource_UnLoad(resource);
6935 IWineD3DResource_Release(resource);
6939 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6942 WINED3DDISPLAYMODE m;
6945 /* All Windowed modes are supported, as is leaving the current mode */
6946 if(pp->Windowed) return TRUE;
6947 if(!pp->BackBufferWidth) return TRUE;
6948 if(!pp->BackBufferHeight) return TRUE;
6950 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
6951 for(i = 0; i < count; i++) {
6952 memset(&m, 0, sizeof(m));
6953 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
6955 ERR("EnumAdapterModes failed\n");
6957 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6958 /* Mode found, it is supported */
6962 /* Mode not found -> not supported */
6966 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6967 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6968 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6970 IWineD3DBaseShaderImpl *shader;
6972 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6974 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6975 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6976 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6980 if(This->depth_blt_texture) {
6981 glDeleteTextures(1, &This->depth_blt_texture);
6982 This->depth_blt_texture = 0;
6984 if (This->depth_blt_rb) {
6985 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
6986 This->depth_blt_rb = 0;
6987 This->depth_blt_rb_w = 0;
6988 This->depth_blt_rb_h = 0;
6992 This->blitter->free_private(iface);
6993 This->frag_pipe->free_private(iface);
6994 This->shader_backend->shader_free_private(iface);
6997 for (i = 0; i < GL_LIMITS(textures); i++) {
6998 /* Textures are recreated below */
6999 glDeleteTextures(1, &This->dummyTextureName[i]);
7000 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7001 This->dummyTextureName[i] = 0;
7005 while(This->numContexts) {
7006 DestroyContext(This, This->contexts[0]);
7008 This->activeContext = NULL;
7009 HeapFree(GetProcessHeap(), 0, swapchain->context);
7010 swapchain->context = NULL;
7011 swapchain->num_contexts = 0;
7014 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7016 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7018 IWineD3DSurfaceImpl *target;
7020 /* Recreate the primary swapchain's context */
7021 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7022 if(swapchain->backBuffer) {
7023 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7025 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7027 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7028 &swapchain->presentParms);
7029 swapchain->num_contexts = 1;
7030 This->activeContext = swapchain->context[0];
7032 create_dummy_textures(This);
7034 hr = This->shader_backend->shader_alloc_private(iface);
7036 ERR("Failed to recreate shader private data\n");
7039 hr = This->frag_pipe->alloc_private(iface);
7041 TRACE("Fragment pipeline private data couldn't be allocated\n");
7044 hr = This->blitter->alloc_private(iface);
7046 TRACE("Blitter private data couldn't be allocated\n");
7053 This->blitter->free_private(iface);
7054 This->frag_pipe->free_private(iface);
7055 This->shader_backend->shader_free_private(iface);
7059 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7060 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7061 IWineD3DSwapChainImpl *swapchain;
7063 BOOL DisplayModeChanged = FALSE;
7064 WINED3DDISPLAYMODE mode;
7065 TRACE("(%p)\n", This);
7067 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7069 ERR("Failed to get the first implicit swapchain\n");
7073 if(!is_display_mode_supported(This, pPresentationParameters)) {
7074 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7075 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7076 pPresentationParameters->BackBufferHeight);
7077 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
7078 return WINED3DERR_INVALIDCALL;
7081 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7082 * on an existing gl context, so there's no real need for recreation.
7084 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7086 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7088 TRACE("New params:\n");
7089 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7090 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7091 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7092 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7093 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7094 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7095 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7096 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7097 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7098 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7099 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7100 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7101 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7103 /* No special treatment of these parameters. Just store them */
7104 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7105 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7106 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7107 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7109 /* What to do about these? */
7110 if(pPresentationParameters->BackBufferCount != 0 &&
7111 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7112 ERR("Cannot change the back buffer count yet\n");
7114 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7115 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7116 ERR("Cannot change the back buffer format yet\n");
7118 if(pPresentationParameters->hDeviceWindow != NULL &&
7119 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7120 ERR("Cannot change the device window yet\n");
7122 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7125 TRACE("Creating the depth stencil buffer\n");
7127 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
7129 pPresentationParameters->BackBufferWidth,
7130 pPresentationParameters->BackBufferHeight,
7131 pPresentationParameters->AutoDepthStencilFormat,
7132 pPresentationParameters->MultiSampleType,
7133 pPresentationParameters->MultiSampleQuality,
7135 &This->auto_depth_stencil_buffer);
7138 ERR("Failed to create the depth stencil buffer\n");
7139 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7140 return WINED3DERR_INVALIDCALL;
7144 /* Reset the depth stencil */
7145 if (pPresentationParameters->EnableAutoDepthStencil)
7146 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7148 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7150 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7152 if(pPresentationParameters->Windowed) {
7153 mode.Width = swapchain->orig_width;
7154 mode.Height = swapchain->orig_height;
7155 mode.RefreshRate = 0;
7156 mode.Format = swapchain->presentParms.BackBufferFormat;
7158 mode.Width = pPresentationParameters->BackBufferWidth;
7159 mode.Height = pPresentationParameters->BackBufferHeight;
7160 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7161 mode.Format = swapchain->presentParms.BackBufferFormat;
7164 /* Should Width == 800 && Height == 0 set 800x600? */
7165 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7166 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7167 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7171 if(!pPresentationParameters->Windowed) {
7172 DisplayModeChanged = TRUE;
7174 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7175 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7177 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7178 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7179 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7181 if(This->auto_depth_stencil_buffer) {
7182 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7186 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7187 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7188 DisplayModeChanged) {
7190 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7192 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7193 if(swapchain->presentParms.Windowed) {
7194 /* switch from windowed to fs */
7195 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7196 pPresentationParameters->BackBufferWidth,
7197 pPresentationParameters->BackBufferHeight);
7199 /* Fullscreen -> fullscreen mode change */
7200 MoveWindow(swapchain->win_handle, 0, 0,
7201 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7204 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7205 /* Fullscreen -> windowed switch */
7206 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7208 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7209 } else if(!pPresentationParameters->Windowed) {
7210 DWORD style = This->style, exStyle = This->exStyle;
7211 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7212 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7213 * Reset to clear up their mess. Guild Wars also loses the device during that.
7217 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7218 pPresentationParameters->BackBufferWidth,
7219 pPresentationParameters->BackBufferHeight);
7220 This->style = style;
7221 This->exStyle = exStyle;
7224 TRACE("Resetting stateblock\n");
7225 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
7226 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
7228 /* Note: No parent needed for initial internal stateblock */
7229 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
7230 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7231 else TRACE("Created stateblock %p\n", This->stateBlock);
7232 This->updateStateBlock = This->stateBlock;
7233 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
7235 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7237 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7240 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7241 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7243 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7249 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7251 /** FIXME: always true at the moment **/
7252 if(!bEnableDialogs) {
7253 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7259 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7260 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7261 TRACE("(%p) : pParameters %p\n", This, pParameters);
7263 *pParameters = This->createParms;
7267 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7268 IWineD3DSwapChain *swapchain;
7270 TRACE("Relaying to swapchain\n");
7272 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7273 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7274 IWineD3DSwapChain_Release(swapchain);
7279 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7280 IWineD3DSwapChain *swapchain;
7282 TRACE("Relaying to swapchain\n");
7284 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7285 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7286 IWineD3DSwapChain_Release(swapchain);
7292 /** ********************************************************
7293 * Notification functions
7294 ** ********************************************************/
7295 /** This function must be called in the release of a resource when ref == 0,
7296 * the contents of resource must still be correct,
7297 * any handles to other resource held by the caller must be closed
7298 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7299 *****************************************************/
7300 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7302 TRACE("(%p) : Adding resource %p\n", This, resource);
7304 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7307 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7309 TRACE("(%p) : Removing resource %p\n", This, resource);
7311 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7314 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7316 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7319 TRACE("(%p) : resource %p\n", This, resource);
7321 context_resource_released((IWineD3DDevice *)This, resource, type);
7324 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7325 case WINED3DRTYPE_SURFACE: {
7328 if (This->d3d_initialized)
7330 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7331 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7332 This->render_targets[i] = NULL;
7335 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7336 This->stencilBufferTarget = NULL;
7342 case WINED3DRTYPE_TEXTURE:
7343 case WINED3DRTYPE_CUBETEXTURE:
7344 case WINED3DRTYPE_VOLUMETEXTURE:
7345 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7346 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7347 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7348 This->stateBlock->textures[counter] = NULL;
7350 if (This->updateStateBlock != This->stateBlock ){
7351 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7352 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7353 This->updateStateBlock->textures[counter] = NULL;
7358 case WINED3DRTYPE_VOLUME:
7359 /* TODO: nothing really? */
7361 case WINED3DRTYPE_BUFFER:
7364 TRACE("Cleaning up stream pointers\n");
7366 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7367 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7368 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7370 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7371 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7372 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7373 This->updateStateBlock->streamSource[streamNumber] = 0;
7374 /* Set changed flag? */
7377 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) */
7378 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7379 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7380 This->stateBlock->streamSource[streamNumber] = 0;
7385 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7386 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7387 This->updateStateBlock->pIndexData = NULL;
7390 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7391 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7392 This->stateBlock->pIndexData = NULL;
7399 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7404 /* Remove the resource from the resourceStore */
7405 device_resource_remove(This, resource);
7407 TRACE("Resource released\n");
7411 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7413 IWineD3DResourceImpl *resource, *cursor;
7415 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7417 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7418 TRACE("enumerating resource %p\n", resource);
7419 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7420 ret = pCallback((IWineD3DResource *) resource, pData);
7421 if(ret == S_FALSE) {
7422 TRACE("Canceling enumeration\n");
7429 /**********************************************************
7430 * IWineD3DDevice VTbl follows
7431 **********************************************************/
7433 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7435 /*** IUnknown methods ***/
7436 IWineD3DDeviceImpl_QueryInterface,
7437 IWineD3DDeviceImpl_AddRef,
7438 IWineD3DDeviceImpl_Release,
7439 /*** IWineD3DDevice methods ***/
7440 IWineD3DDeviceImpl_GetParent,
7441 /*** Creation methods**/
7442 IWineD3DDeviceImpl_CreateBuffer,
7443 IWineD3DDeviceImpl_CreateVertexBuffer,
7444 IWineD3DDeviceImpl_CreateIndexBuffer,
7445 IWineD3DDeviceImpl_CreateStateBlock,
7446 IWineD3DDeviceImpl_CreateSurface,
7447 IWineD3DDeviceImpl_CreateRendertargetView,
7448 IWineD3DDeviceImpl_CreateTexture,
7449 IWineD3DDeviceImpl_CreateVolumeTexture,
7450 IWineD3DDeviceImpl_CreateVolume,
7451 IWineD3DDeviceImpl_CreateCubeTexture,
7452 IWineD3DDeviceImpl_CreateQuery,
7453 IWineD3DDeviceImpl_CreateSwapChain,
7454 IWineD3DDeviceImpl_CreateVertexDeclaration,
7455 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7456 IWineD3DDeviceImpl_CreateVertexShader,
7457 IWineD3DDeviceImpl_CreatePixelShader,
7458 IWineD3DDeviceImpl_CreatePalette,
7459 /*** Odd functions **/
7460 IWineD3DDeviceImpl_Init3D,
7461 IWineD3DDeviceImpl_InitGDI,
7462 IWineD3DDeviceImpl_Uninit3D,
7463 IWineD3DDeviceImpl_UninitGDI,
7464 IWineD3DDeviceImpl_SetMultithreaded,
7465 IWineD3DDeviceImpl_EvictManagedResources,
7466 IWineD3DDeviceImpl_GetAvailableTextureMem,
7467 IWineD3DDeviceImpl_GetBackBuffer,
7468 IWineD3DDeviceImpl_GetCreationParameters,
7469 IWineD3DDeviceImpl_GetDeviceCaps,
7470 IWineD3DDeviceImpl_GetDirect3D,
7471 IWineD3DDeviceImpl_GetDisplayMode,
7472 IWineD3DDeviceImpl_SetDisplayMode,
7473 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7474 IWineD3DDeviceImpl_GetRasterStatus,
7475 IWineD3DDeviceImpl_GetSwapChain,
7476 IWineD3DDeviceImpl_Reset,
7477 IWineD3DDeviceImpl_SetDialogBoxMode,
7478 IWineD3DDeviceImpl_SetCursorProperties,
7479 IWineD3DDeviceImpl_SetCursorPosition,
7480 IWineD3DDeviceImpl_ShowCursor,
7481 IWineD3DDeviceImpl_TestCooperativeLevel,
7482 /*** Getters and setters **/
7483 IWineD3DDeviceImpl_SetClipPlane,
7484 IWineD3DDeviceImpl_GetClipPlane,
7485 IWineD3DDeviceImpl_SetClipStatus,
7486 IWineD3DDeviceImpl_GetClipStatus,
7487 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7488 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7489 IWineD3DDeviceImpl_SetDepthStencilSurface,
7490 IWineD3DDeviceImpl_GetDepthStencilSurface,
7491 IWineD3DDeviceImpl_SetGammaRamp,
7492 IWineD3DDeviceImpl_GetGammaRamp,
7493 IWineD3DDeviceImpl_SetIndices,
7494 IWineD3DDeviceImpl_GetIndices,
7495 IWineD3DDeviceImpl_SetBaseVertexIndex,
7496 IWineD3DDeviceImpl_GetBaseVertexIndex,
7497 IWineD3DDeviceImpl_SetLight,
7498 IWineD3DDeviceImpl_GetLight,
7499 IWineD3DDeviceImpl_SetLightEnable,
7500 IWineD3DDeviceImpl_GetLightEnable,
7501 IWineD3DDeviceImpl_SetMaterial,
7502 IWineD3DDeviceImpl_GetMaterial,
7503 IWineD3DDeviceImpl_SetNPatchMode,
7504 IWineD3DDeviceImpl_GetNPatchMode,
7505 IWineD3DDeviceImpl_SetPaletteEntries,
7506 IWineD3DDeviceImpl_GetPaletteEntries,
7507 IWineD3DDeviceImpl_SetPixelShader,
7508 IWineD3DDeviceImpl_GetPixelShader,
7509 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7510 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7511 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7512 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7513 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7514 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7515 IWineD3DDeviceImpl_SetRenderState,
7516 IWineD3DDeviceImpl_GetRenderState,
7517 IWineD3DDeviceImpl_SetRenderTarget,
7518 IWineD3DDeviceImpl_GetRenderTarget,
7519 IWineD3DDeviceImpl_SetFrontBackBuffers,
7520 IWineD3DDeviceImpl_SetSamplerState,
7521 IWineD3DDeviceImpl_GetSamplerState,
7522 IWineD3DDeviceImpl_SetScissorRect,
7523 IWineD3DDeviceImpl_GetScissorRect,
7524 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7525 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7526 IWineD3DDeviceImpl_SetStreamSource,
7527 IWineD3DDeviceImpl_GetStreamSource,
7528 IWineD3DDeviceImpl_SetStreamSourceFreq,
7529 IWineD3DDeviceImpl_GetStreamSourceFreq,
7530 IWineD3DDeviceImpl_SetTexture,
7531 IWineD3DDeviceImpl_GetTexture,
7532 IWineD3DDeviceImpl_SetTextureStageState,
7533 IWineD3DDeviceImpl_GetTextureStageState,
7534 IWineD3DDeviceImpl_SetTransform,
7535 IWineD3DDeviceImpl_GetTransform,
7536 IWineD3DDeviceImpl_SetVertexDeclaration,
7537 IWineD3DDeviceImpl_GetVertexDeclaration,
7538 IWineD3DDeviceImpl_SetVertexShader,
7539 IWineD3DDeviceImpl_GetVertexShader,
7540 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7541 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7542 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7543 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7544 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7545 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7546 IWineD3DDeviceImpl_SetViewport,
7547 IWineD3DDeviceImpl_GetViewport,
7548 IWineD3DDeviceImpl_MultiplyTransform,
7549 IWineD3DDeviceImpl_ValidateDevice,
7550 IWineD3DDeviceImpl_ProcessVertices,
7551 /*** State block ***/
7552 IWineD3DDeviceImpl_BeginStateBlock,
7553 IWineD3DDeviceImpl_EndStateBlock,
7554 /*** Scene management ***/
7555 IWineD3DDeviceImpl_BeginScene,
7556 IWineD3DDeviceImpl_EndScene,
7557 IWineD3DDeviceImpl_Present,
7558 IWineD3DDeviceImpl_Clear,
7559 IWineD3DDeviceImpl_ClearRendertargetView,
7561 IWineD3DDeviceImpl_SetPrimitiveType,
7562 IWineD3DDeviceImpl_GetPrimitiveType,
7563 IWineD3DDeviceImpl_DrawPrimitive,
7564 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7565 IWineD3DDeviceImpl_DrawPrimitiveUP,
7566 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7567 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7568 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7569 IWineD3DDeviceImpl_DrawRectPatch,
7570 IWineD3DDeviceImpl_DrawTriPatch,
7571 IWineD3DDeviceImpl_DeletePatch,
7572 IWineD3DDeviceImpl_ColorFill,
7573 IWineD3DDeviceImpl_UpdateTexture,
7574 IWineD3DDeviceImpl_UpdateSurface,
7575 IWineD3DDeviceImpl_GetFrontBufferData,
7576 /*** object tracking ***/
7577 IWineD3DDeviceImpl_EnumResources
7580 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7581 WINED3DRS_ALPHABLENDENABLE ,
7582 WINED3DRS_ALPHAFUNC ,
7583 WINED3DRS_ALPHAREF ,
7584 WINED3DRS_ALPHATESTENABLE ,
7586 WINED3DRS_COLORWRITEENABLE ,
7587 WINED3DRS_DESTBLEND ,
7588 WINED3DRS_DITHERENABLE ,
7589 WINED3DRS_FILLMODE ,
7590 WINED3DRS_FOGDENSITY ,
7592 WINED3DRS_FOGSTART ,
7593 WINED3DRS_LASTPIXEL ,
7594 WINED3DRS_SHADEMODE ,
7595 WINED3DRS_SRCBLEND ,
7596 WINED3DRS_STENCILENABLE ,
7597 WINED3DRS_STENCILFAIL ,
7598 WINED3DRS_STENCILFUNC ,
7599 WINED3DRS_STENCILMASK ,
7600 WINED3DRS_STENCILPASS ,
7601 WINED3DRS_STENCILREF ,
7602 WINED3DRS_STENCILWRITEMASK ,
7603 WINED3DRS_STENCILZFAIL ,
7604 WINED3DRS_TEXTUREFACTOR ,
7615 WINED3DRS_ZWRITEENABLE
7618 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7619 WINED3DTSS_ALPHAARG0 ,
7620 WINED3DTSS_ALPHAARG1 ,
7621 WINED3DTSS_ALPHAARG2 ,
7622 WINED3DTSS_ALPHAOP ,
7623 WINED3DTSS_BUMPENVLOFFSET ,
7624 WINED3DTSS_BUMPENVLSCALE ,
7625 WINED3DTSS_BUMPENVMAT00 ,
7626 WINED3DTSS_BUMPENVMAT01 ,
7627 WINED3DTSS_BUMPENVMAT10 ,
7628 WINED3DTSS_BUMPENVMAT11 ,
7629 WINED3DTSS_COLORARG0 ,
7630 WINED3DTSS_COLORARG1 ,
7631 WINED3DTSS_COLORARG2 ,
7632 WINED3DTSS_COLOROP ,
7633 WINED3DTSS_RESULTARG ,
7634 WINED3DTSS_TEXCOORDINDEX ,
7635 WINED3DTSS_TEXTURETRANSFORMFLAGS
7638 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7639 WINED3DSAMP_ADDRESSU ,
7640 WINED3DSAMP_ADDRESSV ,
7641 WINED3DSAMP_ADDRESSW ,
7642 WINED3DSAMP_BORDERCOLOR ,
7643 WINED3DSAMP_MAGFILTER ,
7644 WINED3DSAMP_MINFILTER ,
7645 WINED3DSAMP_MIPFILTER ,
7646 WINED3DSAMP_MIPMAPLODBIAS ,
7647 WINED3DSAMP_MAXMIPLEVEL ,
7648 WINED3DSAMP_MAXANISOTROPY ,
7649 WINED3DSAMP_SRGBTEXTURE ,
7650 WINED3DSAMP_ELEMENTINDEX
7653 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7655 WINED3DRS_AMBIENTMATERIALSOURCE ,
7656 WINED3DRS_CLIPPING ,
7657 WINED3DRS_CLIPPLANEENABLE ,
7658 WINED3DRS_COLORVERTEX ,
7659 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7660 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7661 WINED3DRS_FOGDENSITY ,
7663 WINED3DRS_FOGSTART ,
7664 WINED3DRS_FOGTABLEMODE ,
7665 WINED3DRS_FOGVERTEXMODE ,
7666 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7667 WINED3DRS_LIGHTING ,
7668 WINED3DRS_LOCALVIEWER ,
7669 WINED3DRS_MULTISAMPLEANTIALIAS ,
7670 WINED3DRS_MULTISAMPLEMASK ,
7671 WINED3DRS_NORMALIZENORMALS ,
7672 WINED3DRS_PATCHEDGESTYLE ,
7673 WINED3DRS_POINTSCALE_A ,
7674 WINED3DRS_POINTSCALE_B ,
7675 WINED3DRS_POINTSCALE_C ,
7676 WINED3DRS_POINTSCALEENABLE ,
7677 WINED3DRS_POINTSIZE ,
7678 WINED3DRS_POINTSIZE_MAX ,
7679 WINED3DRS_POINTSIZE_MIN ,
7680 WINED3DRS_POINTSPRITEENABLE ,
7681 WINED3DRS_RANGEFOGENABLE ,
7682 WINED3DRS_SPECULARMATERIALSOURCE ,
7683 WINED3DRS_TWEENFACTOR ,
7684 WINED3DRS_VERTEXBLEND ,
7685 WINED3DRS_CULLMODE ,
7689 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7690 WINED3DTSS_TEXCOORDINDEX ,
7691 WINED3DTSS_TEXTURETRANSFORMFLAGS
7694 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7695 WINED3DSAMP_DMAPOFFSET
7698 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7699 DWORD rep = This->StateTable[state].representative;
7703 WineD3DContext *context;
7706 for(i = 0; i < This->numContexts; i++) {
7707 context = This->contexts[i];
7708 if(isStateDirty(context, rep)) continue;
7710 context->dirtyArray[context->numDirtyEntries++] = rep;
7713 context->isStateDirty[idx] |= (1 << shift);
7717 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7718 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7719 /* The drawable size of a pbuffer render target is the current pbuffer size
7721 *width = dev->pbufferWidth;
7722 *height = dev->pbufferHeight;
7725 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7726 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7728 *width = This->pow2Width;
7729 *height = This->pow2Height;
7732 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7733 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7734 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7735 * current context's drawable, which is the size of the back buffer of the swapchain
7736 * the active context belongs to. The back buffer of the swapchain is stored as the
7737 * surface the context belongs to.
7739 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7740 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;