push 862965e7f7bbbfb960006fcded9111ae18c06ef6
[wine/hacks.git] / dlls / wined3d / device.c
bloba1ed4dc1e7a612e9e96a091ad8410b5c9d2973c0
1 /*
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
28 #include "config.h"
29 #include <stdio.h>
30 #ifdef HAVE_FLOAT_H
31 # include <float.h>
32 #endif
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 */
47 0.0f, /* Range */
48 0.0f, /* Falloff */
49 0.0f, 0.0f, 0.0f, /* Attenuation 0,1,2 */
50 0.0f, /* Theta */
51 0.0f /* Phi */
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:
72 return GL_POINTS;
74 case WINED3DPT_LINELIST:
75 return GL_LINES;
77 case WINED3DPT_LINESTRIP:
78 return GL_LINE_STRIP;
80 case WINED3DPT_TRIANGLELIST:
81 return GL_TRIANGLES;
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;
101 default:
102 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
103 return GL_NONE;
107 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
109 switch(primitive_type)
111 case GL_POINTS:
112 return WINED3DPT_POINTLIST;
114 case GL_LINES:
115 return WINED3DPT_LINELIST;
117 case GL_LINE_STRIP:
118 return WINED3DPT_LINESTRIP;
120 case GL_TRIANGLES:
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;
141 default:
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;
165 else
167 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
168 *regnum = ~0U;
169 return FALSE;
172 return TRUE;
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;
183 unsigned int i;
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;
197 BOOL stride_used;
198 unsigned int idx;
199 DWORD stride;
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]);
210 buffer_object = 0;
211 data = (BYTE *)This->stateBlock->streamSource[element->input_slot];
213 else
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);
226 buffer_object = 0;
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");
234 if (fixup)
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;
242 if (!warned)
244 /* This may be bad with the fixed function pipeline. */
245 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
246 warned = TRUE;
251 data += element->offset;
253 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
255 if (use_vshader)
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);
265 else
267 idx = element->output_slot;
268 stride_used = TRUE;
271 else
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));
277 stride_used = FALSE;
279 else
281 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
285 if (stride_used)
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
310 * own again.
312 * NULL streams won't be recorded in the array, UP streams won't be either. A stream is only
313 * once in there. */
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;
328 e->stream_idx = 0;
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)
335 unsigned int i;
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);
382 *ppobj = This;
383 return S_OK;
385 *ppobj = NULL;
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);
394 return refCount;
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);
403 if (!refCount) {
404 UINT i;
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);
428 This = NULL;
430 return refCount;
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);
440 return WINED3D_OK;
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;
449 HRESULT hr;
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));
454 if (!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);
467 if (FAILED(hr))
469 WARN("Failed to initialize resource, returning %#x\n", hr);
470 HeapFree(GetProcessHeap(), 0, object);
471 return hr;
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);
480 if (data)
482 BYTE *ptr;
484 hr = IWineD3DBuffer_Map((IWineD3DBuffer *)object, 0, desc->byte_width, &ptr, 0);
485 if (FAILED(hr))
487 ERR("Failed to map buffer, hr %#x\n", hr);
488 IWineD3DBuffer_Release((IWineD3DBuffer *)object);
489 return hr;
492 memcpy(ptr, data, desc->byte_width);
494 hr = IWineD3DBuffer_Unmap((IWineD3DBuffer *)object);
495 if (FAILED(hr))
497 ERR("Failed to unmap buffer, hr %#x\n", hr);
498 IWineD3DBuffer_Release((IWineD3DBuffer *)object);
499 return hr;
503 *buffer = (IWineD3DBuffer *)object;
505 return WINED3D_OK;
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;
516 HRESULT hr;
517 BOOL conv;
519 if(Size == 0) {
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));
533 if (!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);
542 if (FAILED(hr))
544 WARN("Failed to initialize resource, returning %#x\n", hr);
545 HeapFree(GetProcessHeap(), 0, object);
546 *ppVertexBuffer = NULL;
547 return hr;
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
567 * dx7 apps.
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");
580 } else {
581 object->flags |= WINED3D_BUFFER_CREATEBO;
583 return WINED3D_OK;
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;
592 HRESULT hr;
594 TRACE("(%p) Creating index buffer\n", This);
596 /* Allocate the storage for the device */
597 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
598 if (!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);
607 if (FAILED(hr))
609 WARN("Failed to initialize resource, returning %#x\n", hr);
610 HeapFree(GetProcessHeap(), 0, object);
611 *ppIndexBuffer = NULL;
612 return hr;
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;
626 return WINED3D_OK;
629 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
632 IWineD3DStateBlockImpl *object;
633 unsigned int i, j;
634 HRESULT temp_result;
636 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
637 if(!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;
647 object->ref = 1;
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);
660 return temp_result;
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 */
669 return WINED3D_OK;
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);
675 else
676 memset(object->streamFreq, 1, sizeof(object->streamFreq));
678 /* Reset the ref and type after kludging it */
679 object->wineD3DDevice = This;
680 object->ref = 1;
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++) {
692 struct list *e;
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++) {
873 struct list *e;
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;
891 } else {
892 FIXME("Unrecognized state block type %d\n", Type);
895 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
896 return WINED3D_OK;
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;
906 HRESULT hr;
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));
917 if (!object)
919 ERR("Failed to allocate surface memory.\n");
920 *ppSurface = NULL;
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);
926 if (FAILED(hr))
928 WARN("Failed to initialize surface, returning %#x.\n", hr);
929 HeapFree(GetProcessHeap(), 0, object);
930 *ppSurface = NULL;
931 return hr;
934 TRACE("(%p) : Created surface %p\n", This, object);
936 *ppSurface = (IWineD3DSurface *)object;
938 return hr;
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));
947 if (!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;
961 return WINED3D_OK;
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;
970 HRESULT hr;
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));
977 if (!object)
979 ERR("Out of memory\n");
980 *ppTexture = NULL;
981 return WINED3DERR_OUTOFVIDEOMEMORY;
984 object->lpVtbl = &IWineD3DTexture_Vtbl;
986 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent);
987 if (FAILED(hr))
989 WARN("Failed to initialize texture, returning %#x\n", hr);
990 HeapFree(GetProcessHeap(), 0, object);
991 *ppTexture = NULL;
992 return hr;
995 *ppTexture = (IWineD3DTexture *)object;
997 TRACE("(%p) : Created texture %p\n", This, object);
999 return WINED3D_OK;
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;
1008 HRESULT hr;
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));
1014 if (!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);
1023 if (FAILED(hr))
1025 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
1026 HeapFree(GetProcessHeap(), 0, object);
1027 *ppVolumeTexture = NULL;
1028 return hr;
1031 TRACE("(%p) : Created volume texture %p.\n", This, object);
1032 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
1034 return WINED3D_OK;
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);
1044 HRESULT hr;
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));
1052 if (!object)
1054 ERR("Out of memory\n");
1055 *ppVolume = NULL;
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);
1062 if (FAILED(hr))
1064 WARN("Failed to initialize resource, returning %#x\n", hr);
1065 HeapFree(GetProcessHeap(), 0, object);
1066 *ppVolume = NULL;
1067 return hr;
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);
1089 return WINED3D_OK;
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 **/
1098 HRESULT hr;
1100 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1101 if (!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);
1110 if (FAILED(hr))
1112 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1113 HeapFree(GetProcessHeap(), 0, object);
1114 *ppCubeTexture = NULL;
1115 return hr;
1118 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1119 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1121 return WINED3D_OK;
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 */
1131 switch(Type) {
1132 case WINED3DQUERYTYPE_OCCLUSION:
1133 TRACE("(%p) occlusion query\n", This);
1134 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1135 hr = WINED3D_OK;
1136 else
1137 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1139 vtable = &IWineD3DOcclusionQuery_Vtbl;
1140 break;
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;
1150 hr = WINED3D_OK;
1151 break;
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:
1165 default:
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) {
1171 return hr;
1174 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1175 if(!object)
1177 ERR("Out of memory\n");
1178 *ppQuery = NULL;
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;
1187 object->ref = 1;
1189 *ppQuery = (IWineD3DQuery *)object;
1191 /* allocated the 'extended' data based on the type of query requested */
1192 switch(Type){
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, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1201 ENTER_GL();
1202 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1203 LEAVE_GL();
1204 break;
1206 case WINED3DQUERYTYPE_EVENT:
1207 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1208 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1210 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1211 ENTER_GL();
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");
1219 LEAVE_GL();
1220 break;
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:
1234 default:
1235 object->extendedData = 0;
1236 FIXME("(%p) Unhandled query type %d\n",This , Type);
1238 TRACE("(%p) : Created Query %p\n", This, object);
1239 return WINED3D_OK;
1242 /*****************************************************************************
1243 * IWineD3DDeviceImpl_SetupFullscreenWindow
1245 * Helper function that modifies a HWND's Style and ExStyle for proper
1246 * fullscreen use.
1248 * Params:
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;
1261 return style;
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;
1271 return exStyle;
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
1313 * Params:
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 */
1344 This->style = 0;
1345 This->exStyle = 0;
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;
1360 HDC hDc;
1361 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1362 HRESULT hr;
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));
1384 if(!object)
1386 ERR("Out of memory\n");
1387 *ppSwapChain = NULL;
1388 return WINED3DERR_OUTOFVIDEOMEMORY;
1391 switch(surface_type) {
1392 case SURFACE_GDI:
1393 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1394 break;
1395 case SURFACE_OPENGL:
1396 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1397 break;
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;
1405 object->ref = 1;
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);
1427 if (NULL == 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))) {
1444 RECT Rect;
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);
1476 } else {
1477 ERR("Failed to create the front buffer\n");
1478 goto error;
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");
1517 hr = E_OUTOFMEMORY;
1518 goto error;
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;
1527 goto error;
1528 } else {
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) {
1538 UINT i;
1540 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1541 if(!object->backBuffer) {
1542 ERR("Out of memory\n");
1543 hr = E_OUTOFMEMORY;
1544 goto error;
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]);
1553 if(SUCCEEDED(hr)) {
1554 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1555 ((IWineD3DSurfaceImpl *)object->backBuffer[i])->Flags |= SFLAG_SWAPCHAIN;
1556 } else {
1557 ERR("Cannot create new back buffer\n");
1558 goto error;
1560 if(surface_type == SURFACE_OPENGL) {
1561 ENTER_GL();
1562 glDrawBuffer(GL_BACK);
1563 checkGLcall("glDrawBuffer(GL_BACK)");
1564 LEAVE_GL();
1567 } else {
1568 object->backBuffer = NULL;
1570 /* Single buffering - draw to front buffer */
1571 if(surface_type == SURFACE_OPENGL) {
1572 ENTER_GL();
1573 glDrawBuffer(GL_FRONT);
1574 checkGLcall("glDrawBuffer(GL_FRONT)");
1575 LEAVE_GL();
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);
1590 } else {
1591 ERR("Failed to create the auto depth stencil\n");
1592 goto error;
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);
1601 return WINED3D_OK;
1603 error:
1604 if (displaymode_set) {
1605 DEVMODEW devmode;
1606 RECT clip_rc;
1608 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1609 ClipCursor(NULL);
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) {
1622 UINT i;
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);
1645 return hr;
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);
1664 return WINED3D_OK;
1665 } else {
1666 TRACE("Swapchain out of range\n");
1667 *pSwapChain = NULL;
1668 return WINED3DERR_INVALIDCALL;
1672 /*****
1673 * Vertex Declaration
1674 *****/
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));
1685 if(!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;
1695 object->ref = 1;
1697 *ppVertexDeclaration = (IWineD3DVertexDeclaration *)object;
1699 hr = vertexdeclaration_init(object, elements, element_count);
1701 if(FAILED(hr)) {
1702 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
1703 *ppVertexDeclaration = NULL;
1706 return hr;
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;
1729 unsigned int size;
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;
1741 idx = 0;
1742 if (has_pos) {
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;
1751 else {
1752 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1753 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1755 elements[idx].usage_idx = 0;
1756 idx++;
1758 if (has_blend && (num_blends > 0)) {
1759 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1760 elements[idx].format = WINED3DFMT_A8R8G8B8;
1761 else {
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;
1767 default:
1768 ERR("Unexpected amount of blend values: %u\n", num_blends);
1771 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1772 elements[idx].usage_idx = 0;
1773 idx++;
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;
1781 else
1782 elements[idx].format = WINED3DFMT_R32_FLOAT;
1783 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
1784 elements[idx].usage_idx = 0;
1785 idx++;
1787 if (has_normal) {
1788 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1789 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
1790 elements[idx].usage_idx = 0;
1791 idx++;
1793 if (has_psize) {
1794 elements[idx].format = WINED3DFMT_R32_FLOAT;
1795 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
1796 elements[idx].usage_idx = 0;
1797 idx++;
1799 if (has_diffuse) {
1800 elements[idx].format = WINED3DFMT_A8R8G8B8;
1801 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1802 elements[idx].usage_idx = 0;
1803 idx++;
1805 if (has_specular) {
1806 elements[idx].format = WINED3DFMT_A8R8G8B8;
1807 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1808 elements[idx].usage_idx = 1;
1809 idx++;
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;
1816 break;
1817 case WINED3DFVF_TEXTUREFORMAT2:
1818 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
1819 break;
1820 case WINED3DFVF_TEXTUREFORMAT3:
1821 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1822 break;
1823 case WINED3DFVF_TEXTUREFORMAT4:
1824 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1825 break;
1827 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
1828 elements[idx].usage_idx = idx2;
1829 idx++;
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;
1843 return size;
1846 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1847 WINED3DVERTEXELEMENT* elements = NULL;
1848 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1849 unsigned int size;
1850 DWORD hr;
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;
1859 return WINED3D_OK;
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));
1873 if (!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);
1889 if (FAILED(hr))
1891 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
1892 IWineD3DVertexShader_Release(*ppVertexShader);
1893 *ppVertexShader = NULL;
1894 return hr;
1897 return hr;
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));
1911 if (!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);
1927 if (FAILED(hr))
1929 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
1930 IWineD3DPixelShader_Release(*ppPixelShader);
1931 *ppPixelShader = NULL;
1932 return hr;
1935 return hr;
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;
1943 HRESULT hr;
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));
1948 if(!object) {
1949 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1950 return E_OUTOFMEMORY;
1953 object->lpVtbl = &IWineD3DPalette_Vtbl;
1954 object->ref = 1;
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));
1961 if(!object->hpal) {
1962 HeapFree( GetProcessHeap(), 0, object);
1963 return E_OUTOFMEMORY;
1966 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1967 if(FAILED(hr)) {
1968 IWineD3DPalette_Release((IWineD3DPalette *) object);
1969 return hr;
1972 *Palette = (IWineD3DPalette *) object;
1974 return WINED3D_OK;
1977 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1978 HBITMAP hbm;
1979 BITMAP bm;
1980 HRESULT hr;
1981 HDC dcb = NULL, dcs = NULL;
1982 WINEDDCOLORKEY colorkey;
1984 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1985 if(hbm)
1987 GetObjectA(hbm, sizeof(BITMAP), &bm);
1988 dcb = CreateCompatibleDC(NULL);
1989 if(!dcb) goto out;
1990 SelectObject(dcb, hbm);
1992 else
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));
1998 bm.bmWidth = 32;
1999 bm.bmHeight = 32;
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);
2004 if(FAILED(hr)) {
2005 ERR("Wine logo requested, but failed to create surface\n");
2006 goto out;
2009 if(dcb) {
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);
2018 } else {
2019 /* Fill the surface with a white color to show that wined3d is there */
2020 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2023 out:
2024 if(dcb) {
2025 DeleteDC(dcb);
2027 if(hbm) {
2028 DeleteObject(hbm);
2030 return;
2033 /* Context activation is done by the caller. */
2034 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2035 unsigned int i;
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 */
2041 ENTER_GL();
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)");
2074 LEAVE_GL();
2077 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
2078 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2080 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2081 IWineD3DSwapChainImpl *swapchain = NULL;
2082 HRESULT hr;
2083 DWORD state;
2084 unsigned int i;
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,
2096 WINED3DSBT_INIT,
2097 (IWineD3DStateBlock **)&This->stateBlock,
2098 NULL);
2099 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2100 WARN("Failed to create stateblock\n");
2101 goto err_out;
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");
2114 goto err_out;
2116 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2117 if(!This->palettes[0]) {
2118 ERR("Out of memory!\n");
2119 goto err_out;
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;
2134 } else {
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);
2144 if (FAILED(hr))
2146 WARN("Failed to create implicit swapchain\n");
2147 goto err_out;
2150 This->NumberOfSwapChains = 1;
2151 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2152 if(!This->swapchains) {
2153 ERR("Out of memory!\n");
2154 goto err_out;
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];
2161 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2163 else {
2164 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2165 This->render_targets[0] = swapchain->frontBuffer;
2166 This->lastActiveRenderTarget = swapchain->frontBuffer;
2168 IWineD3DSurface_AddRef(This->render_targets[0]);
2169 This->activeContext = swapchain->context[0];
2170 This->lastThread = GetCurrentThreadId();
2172 /* Depth Stencil support */
2173 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2174 if (NULL != This->stencilBufferTarget) {
2175 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2178 hr = This->shader_backend->shader_alloc_private(iface);
2179 if(FAILED(hr)) {
2180 TRACE("Shader private data couldn't be allocated\n");
2181 goto err_out;
2183 hr = This->frag_pipe->alloc_private(iface);
2184 if(FAILED(hr)) {
2185 TRACE("Fragment pipeline private data couldn't be allocated\n");
2186 goto err_out;
2188 hr = This->blitter->alloc_private(iface);
2189 if(FAILED(hr)) {
2190 TRACE("Blitter private data couldn't be allocated\n");
2191 goto err_out;
2194 /* Set up some starting GL setup */
2196 /* Setup all the devices defaults */
2197 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2198 create_dummy_textures(This);
2200 ENTER_GL();
2202 /* Initialize the current view state */
2203 This->view_ident = 1;
2204 This->contexts[0]->last_was_rhw = 0;
2205 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2206 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2208 switch(wined3d_settings.offscreen_rendering_mode) {
2209 case ORM_FBO:
2210 case ORM_PBUFFER:
2211 This->offscreenBuffer = GL_BACK;
2212 break;
2214 case ORM_BACKBUFFER:
2216 if(This->activeContext->aux_buffers > 0) {
2217 TRACE("Using auxilliary buffer for offscreen rendering\n");
2218 This->offscreenBuffer = GL_AUX0;
2219 } else {
2220 TRACE("Using back buffer for offscreen rendering\n");
2221 This->offscreenBuffer = GL_BACK;
2226 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2227 LEAVE_GL();
2229 /* Clear the screen */
2230 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2231 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2232 0x00, 1.0f, 0);
2234 This->d3d_initialized = TRUE;
2236 if(wined3d_settings.logo) {
2237 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2239 This->highest_dirty_ps_const = 0;
2240 This->highest_dirty_vs_const = 0;
2241 return WINED3D_OK;
2243 err_out:
2244 HeapFree(GetProcessHeap(), 0, This->render_targets);
2245 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2246 HeapFree(GetProcessHeap(), 0, This->swapchains);
2247 This->NumberOfSwapChains = 0;
2248 if(This->palettes) {
2249 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2250 HeapFree(GetProcessHeap(), 0, This->palettes);
2252 This->NumberOfPalettes = 0;
2253 if(swapchain) {
2254 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2256 if(This->stateBlock) {
2257 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2258 This->stateBlock = NULL;
2260 if (This->blit_priv) {
2261 This->blitter->free_private(iface);
2263 if (This->fragment_priv) {
2264 This->frag_pipe->free_private(iface);
2266 if (This->shader_priv) {
2267 This->shader_backend->shader_free_private(iface);
2269 return hr;
2272 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2273 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2275 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2276 IWineD3DSwapChainImpl *swapchain = NULL;
2277 HRESULT hr;
2279 /* Setup the implicit swapchain */
2280 TRACE("Creating implicit swapchain\n");
2281 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2282 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2283 if (FAILED(hr))
2285 WARN("Failed to create implicit swapchain\n");
2286 goto err_out;
2289 This->NumberOfSwapChains = 1;
2290 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2291 if(!This->swapchains) {
2292 ERR("Out of memory!\n");
2293 goto err_out;
2295 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2296 return WINED3D_OK;
2298 err_out:
2299 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2300 return hr;
2303 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2305 IWineD3DResource_UnLoad(resource);
2306 IWineD3DResource_Release(resource);
2307 return WINED3D_OK;
2310 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2311 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2312 int sampler;
2313 UINT i;
2314 TRACE("(%p)\n", This);
2316 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2318 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2319 * it was created. Thus make sure a context is active for the glDelete* calls
2321 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2323 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2325 /* Unload resources */
2326 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2328 TRACE("Deleting high order patches\n");
2329 for(i = 0; i < PATCHMAP_SIZE; i++) {
2330 struct list *e1, *e2;
2331 struct WineD3DRectPatch *patch;
2332 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2333 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2334 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2338 /* Delete the palette conversion shader if it is around */
2339 if(This->paletteConversionShader) {
2340 ENTER_GL();
2341 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2342 LEAVE_GL();
2343 This->paletteConversionShader = 0;
2346 /* Delete the pbuffer context if there is any */
2347 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2349 /* Delete the mouse cursor texture */
2350 if(This->cursorTexture) {
2351 ENTER_GL();
2352 glDeleteTextures(1, &This->cursorTexture);
2353 LEAVE_GL();
2354 This->cursorTexture = 0;
2357 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2358 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2360 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2361 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2364 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2365 * private data, it might contain opengl pointers
2367 if(This->depth_blt_texture) {
2368 ENTER_GL();
2369 glDeleteTextures(1, &This->depth_blt_texture);
2370 LEAVE_GL();
2371 This->depth_blt_texture = 0;
2373 if (This->depth_blt_rb) {
2374 ENTER_GL();
2375 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2376 LEAVE_GL();
2377 This->depth_blt_rb = 0;
2378 This->depth_blt_rb_w = 0;
2379 This->depth_blt_rb_h = 0;
2382 /* Release the update stateblock */
2383 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2384 if(This->updateStateBlock != This->stateBlock)
2385 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2387 This->updateStateBlock = NULL;
2389 { /* because were not doing proper internal refcounts releasing the primary state block
2390 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2391 to set this->stateBlock = NULL; first */
2392 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2393 This->stateBlock = NULL;
2395 /* Release the stateblock */
2396 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2397 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2401 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2402 This->blitter->free_private(iface);
2403 This->frag_pipe->free_private(iface);
2404 This->shader_backend->shader_free_private(iface);
2406 /* Release the buffers (with sanity checks)*/
2407 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2408 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2409 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2410 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2412 This->stencilBufferTarget = NULL;
2414 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2415 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2416 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2418 TRACE("Setting rendertarget to NULL\n");
2419 This->render_targets[0] = NULL;
2421 if (This->auto_depth_stencil_buffer) {
2422 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2423 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2425 This->auto_depth_stencil_buffer = NULL;
2428 for(i=0; i < This->NumberOfSwapChains; i++) {
2429 TRACE("Releasing the implicit swapchain %d\n", i);
2430 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2431 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2435 HeapFree(GetProcessHeap(), 0, This->swapchains);
2436 This->swapchains = NULL;
2437 This->NumberOfSwapChains = 0;
2439 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2440 HeapFree(GetProcessHeap(), 0, This->palettes);
2441 This->palettes = NULL;
2442 This->NumberOfPalettes = 0;
2444 HeapFree(GetProcessHeap(), 0, This->render_targets);
2445 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2446 This->render_targets = NULL;
2447 This->draw_buffers = NULL;
2449 This->d3d_initialized = FALSE;
2450 return WINED3D_OK;
2453 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2454 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2455 unsigned int i;
2457 for(i=0; i < This->NumberOfSwapChains; i++) {
2458 TRACE("Releasing the implicit swapchain %d\n", i);
2459 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2460 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2464 HeapFree(GetProcessHeap(), 0, This->swapchains);
2465 This->swapchains = NULL;
2466 This->NumberOfSwapChains = 0;
2467 return WINED3D_OK;
2470 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2471 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2472 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2474 * There is no way to deactivate thread safety once it is enabled.
2476 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2477 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2479 /*For now just store the flag(needed in case of ddraw) */
2480 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2482 return;
2485 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2486 const WINED3DDISPLAYMODE* pMode) {
2487 DEVMODEW devmode;
2488 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2489 LONG ret;
2490 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &GLINFO_LOCATION);
2491 RECT clip_rc;
2493 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2495 /* Resize the screen even without a window:
2496 * The app could have unset it with SetCooperativeLevel, but not called
2497 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2498 * but we don't have any hwnd
2501 memset(&devmode, 0, sizeof(devmode));
2502 devmode.dmSize = sizeof(devmode);
2503 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2504 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2505 devmode.dmPelsWidth = pMode->Width;
2506 devmode.dmPelsHeight = pMode->Height;
2508 devmode.dmDisplayFrequency = pMode->RefreshRate;
2509 if (pMode->RefreshRate != 0) {
2510 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2513 /* Only change the mode if necessary */
2514 if( (This->ddraw_width == pMode->Width) &&
2515 (This->ddraw_height == pMode->Height) &&
2516 (This->ddraw_format == pMode->Format) &&
2517 (pMode->RefreshRate == 0) ) {
2518 return WINED3D_OK;
2521 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2522 if (ret != DISP_CHANGE_SUCCESSFUL) {
2523 if(devmode.dmDisplayFrequency != 0) {
2524 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2525 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2526 devmode.dmDisplayFrequency = 0;
2527 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2529 if(ret != DISP_CHANGE_SUCCESSFUL) {
2530 return WINED3DERR_NOTAVAILABLE;
2534 /* Store the new values */
2535 This->ddraw_width = pMode->Width;
2536 This->ddraw_height = pMode->Height;
2537 This->ddraw_format = pMode->Format;
2539 /* And finally clip mouse to our screen */
2540 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2541 ClipCursor(&clip_rc);
2543 return WINED3D_OK;
2546 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2547 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2548 *ppD3D= This->wineD3D;
2549 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2550 IWineD3D_AddRef(*ppD3D);
2551 return WINED3D_OK;
2554 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2555 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2557 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2558 (This->adapter->TextureRam/(1024*1024)),
2559 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2560 /* return simulated texture memory left */
2561 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2564 /*****
2565 * Get / Set Stream Source
2566 *****/
2567 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2568 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2570 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2571 IWineD3DBuffer *oldSrc;
2573 if (StreamNumber >= MAX_STREAMS) {
2574 WARN("Stream out of range %d\n", StreamNumber);
2575 return WINED3DERR_INVALIDCALL;
2576 } else if(OffsetInBytes & 0x3) {
2577 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2578 return WINED3DERR_INVALIDCALL;
2581 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2582 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2584 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2586 if(oldSrc == pStreamData &&
2587 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2588 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2589 TRACE("Application is setting the old values over, nothing to do\n");
2590 return WINED3D_OK;
2593 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2594 if (pStreamData) {
2595 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2596 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2599 /* Handle recording of state blocks */
2600 if (This->isRecordingState) {
2601 TRACE("Recording... not performing anything\n");
2602 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2603 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2604 return WINED3D_OK;
2607 if (pStreamData != NULL) {
2608 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2609 IWineD3DBuffer_AddRef(pStreamData);
2611 if (oldSrc != NULL) {
2612 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2613 IWineD3DBuffer_Release(oldSrc);
2616 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2618 return WINED3D_OK;
2621 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2622 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2626 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2627 This->stateBlock->streamSource[StreamNumber],
2628 This->stateBlock->streamOffset[StreamNumber],
2629 This->stateBlock->streamStride[StreamNumber]);
2631 if (StreamNumber >= MAX_STREAMS) {
2632 WARN("Stream out of range %d\n", StreamNumber);
2633 return WINED3DERR_INVALIDCALL;
2635 *pStream = This->stateBlock->streamSource[StreamNumber];
2636 *pStride = This->stateBlock->streamStride[StreamNumber];
2637 if (pOffset) {
2638 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2641 if (*pStream != NULL) {
2642 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2644 return WINED3D_OK;
2647 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2648 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2649 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2650 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2652 /* Verify input at least in d3d9 this is invalid*/
2653 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2654 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2655 return WINED3DERR_INVALIDCALL;
2657 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2658 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2659 return WINED3DERR_INVALIDCALL;
2661 if( Divider == 0 ){
2662 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2663 return WINED3DERR_INVALIDCALL;
2666 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2667 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2669 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2670 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2672 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2673 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2674 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2677 return WINED3D_OK;
2680 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2681 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2683 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2684 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2686 TRACE("(%p) : returning %d\n", This, *Divider);
2688 return WINED3D_OK;
2691 /*****
2692 * Get / Set & Multiply Transform
2693 *****/
2694 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2695 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2697 /* Most of this routine, comments included copied from ddraw tree initially: */
2698 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2700 /* Handle recording of state blocks */
2701 if (This->isRecordingState) {
2702 TRACE("Recording... not performing anything\n");
2703 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2704 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2705 return WINED3D_OK;
2709 * If the new matrix is the same as the current one,
2710 * we cut off any further processing. this seems to be a reasonable
2711 * optimization because as was noticed, some apps (warcraft3 for example)
2712 * tend towards setting the same matrix repeatedly for some reason.
2714 * From here on we assume that the new matrix is different, wherever it matters.
2716 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2717 TRACE("The app is setting the same matrix over again\n");
2718 return WINED3D_OK;
2719 } else {
2720 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2724 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2725 where ViewMat = Camera space, WorldMat = world space.
2727 In OpenGL, camera and world space is combined into GL_MODELVIEW
2728 matrix. The Projection matrix stay projection matrix.
2731 /* Capture the times we can just ignore the change for now */
2732 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2733 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2734 /* Handled by the state manager */
2737 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2738 return WINED3D_OK;
2741 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2742 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2743 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2744 *pMatrix = This->stateBlock->transforms[State];
2745 return WINED3D_OK;
2748 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2749 const WINED3DMATRIX *mat = NULL;
2750 WINED3DMATRIX temp;
2752 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2753 * below means it will be recorded in a state block change, but it
2754 * works regardless where it is recorded.
2755 * If this is found to be wrong, change to StateBlock.
2757 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2758 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2760 if (State <= HIGHEST_TRANSFORMSTATE)
2762 mat = &This->updateStateBlock->transforms[State];
2763 } else {
2764 FIXME("Unhandled transform state!!\n");
2767 multiply_matrix(&temp, mat, pMatrix);
2769 /* Apply change via set transform - will reapply to eg. lights this way */
2770 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2773 /*****
2774 * Get / Set Light
2775 *****/
2776 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2777 you can reference any indexes you want as long as that number max are enabled at any
2778 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2779 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2780 but when recording, just build a chain pretty much of commands to be replayed. */
2782 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2783 float rho;
2784 PLIGHTINFOEL *object = NULL;
2785 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2786 struct list *e;
2788 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2789 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2791 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2792 * the gl driver.
2794 if(!pLight) {
2795 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2796 return WINED3DERR_INVALIDCALL;
2799 switch(pLight->Type) {
2800 case WINED3DLIGHT_POINT:
2801 case WINED3DLIGHT_SPOT:
2802 case WINED3DLIGHT_PARALLELPOINT:
2803 case WINED3DLIGHT_GLSPOT:
2804 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2805 * most wanted
2807 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2809 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2810 return WINED3DERR_INVALIDCALL;
2812 break;
2814 case WINED3DLIGHT_DIRECTIONAL:
2815 /* Ignores attenuation */
2816 break;
2818 default:
2819 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2820 return WINED3DERR_INVALIDCALL;
2823 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2824 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2825 if(object->OriginalIndex == Index) break;
2826 object = NULL;
2829 if(!object) {
2830 TRACE("Adding new light\n");
2831 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2832 if(!object) {
2833 ERR("Out of memory error when allocating a light\n");
2834 return E_OUTOFMEMORY;
2836 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2837 object->glIndex = -1;
2838 object->OriginalIndex = Index;
2839 object->changed = TRUE;
2842 /* Initialize the object */
2843 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,
2844 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2845 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2846 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2847 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2848 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2849 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2851 /* Save away the information */
2852 object->OriginalParms = *pLight;
2854 switch (pLight->Type) {
2855 case WINED3DLIGHT_POINT:
2856 /* Position */
2857 object->lightPosn[0] = pLight->Position.x;
2858 object->lightPosn[1] = pLight->Position.y;
2859 object->lightPosn[2] = pLight->Position.z;
2860 object->lightPosn[3] = 1.0f;
2861 object->cutoff = 180.0f;
2862 /* FIXME: Range */
2863 break;
2865 case WINED3DLIGHT_DIRECTIONAL:
2866 /* Direction */
2867 object->lightPosn[0] = -pLight->Direction.x;
2868 object->lightPosn[1] = -pLight->Direction.y;
2869 object->lightPosn[2] = -pLight->Direction.z;
2870 object->lightPosn[3] = 0.0f;
2871 object->exponent = 0.0f;
2872 object->cutoff = 180.0f;
2873 break;
2875 case WINED3DLIGHT_SPOT:
2876 /* Position */
2877 object->lightPosn[0] = pLight->Position.x;
2878 object->lightPosn[1] = pLight->Position.y;
2879 object->lightPosn[2] = pLight->Position.z;
2880 object->lightPosn[3] = 1.0f;
2882 /* Direction */
2883 object->lightDirn[0] = pLight->Direction.x;
2884 object->lightDirn[1] = pLight->Direction.y;
2885 object->lightDirn[2] = pLight->Direction.z;
2886 object->lightDirn[3] = 1.0f;
2889 * opengl-ish and d3d-ish spot lights use too different models for the
2890 * light "intensity" as a function of the angle towards the main light direction,
2891 * so we only can approximate very roughly.
2892 * however spot lights are rather rarely used in games (if ever used at all).
2893 * furthermore if still used, probably nobody pays attention to such details.
2895 if (pLight->Falloff == 0) {
2896 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2897 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2898 * will always be 1.0 for both of them, and we don't have to care for the
2899 * rest of the rather complex calculation
2901 object->exponent = 0.0f;
2902 } else {
2903 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2904 if (rho < 0.0001f) rho = 0.0001f;
2905 object->exponent = -0.3f/logf(cosf(rho/2));
2907 if (object->exponent > 128.0f)
2909 object->exponent = 128.0f;
2911 object->cutoff = pLight->Phi*90/M_PI;
2913 /* FIXME: Range */
2914 break;
2916 default:
2917 FIXME("Unrecognized light type %d\n", pLight->Type);
2920 /* Update the live definitions if the light is currently assigned a glIndex */
2921 if (object->glIndex != -1 && !This->isRecordingState) {
2922 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2924 return WINED3D_OK;
2927 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2928 PLIGHTINFOEL *lightInfo = NULL;
2929 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2930 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2931 struct list *e;
2932 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2934 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2935 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2936 if(lightInfo->OriginalIndex == Index) break;
2937 lightInfo = NULL;
2940 if (lightInfo == NULL) {
2941 TRACE("Light information requested but light not defined\n");
2942 return WINED3DERR_INVALIDCALL;
2945 *pLight = lightInfo->OriginalParms;
2946 return WINED3D_OK;
2949 /*****
2950 * Get / Set Light Enable
2951 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2952 *****/
2953 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2954 PLIGHTINFOEL *lightInfo = NULL;
2955 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2956 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2957 struct list *e;
2958 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2960 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2961 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2962 if(lightInfo->OriginalIndex == Index) break;
2963 lightInfo = NULL;
2965 TRACE("Found light: %p\n", lightInfo);
2967 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2968 if (lightInfo == NULL) {
2970 TRACE("Light enabled requested but light not defined, so defining one!\n");
2971 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2973 /* Search for it again! Should be fairly quick as near head of list */
2974 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2975 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2976 if(lightInfo->OriginalIndex == Index) break;
2977 lightInfo = NULL;
2979 if (lightInfo == NULL) {
2980 FIXME("Adding default lights has failed dismally\n");
2981 return WINED3DERR_INVALIDCALL;
2985 lightInfo->enabledChanged = TRUE;
2986 if(!Enable) {
2987 if(lightInfo->glIndex != -1) {
2988 if(!This->isRecordingState) {
2989 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2992 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2993 lightInfo->glIndex = -1;
2994 } else {
2995 TRACE("Light already disabled, nothing to do\n");
2997 lightInfo->enabled = FALSE;
2998 } else {
2999 lightInfo->enabled = TRUE;
3000 if (lightInfo->glIndex != -1) {
3001 /* nop */
3002 TRACE("Nothing to do as light was enabled\n");
3003 } else {
3004 int i;
3005 /* Find a free gl light */
3006 for(i = 0; i < This->maxConcurrentLights; i++) {
3007 if(This->updateStateBlock->activeLights[i] == NULL) {
3008 This->updateStateBlock->activeLights[i] = lightInfo;
3009 lightInfo->glIndex = i;
3010 break;
3013 if(lightInfo->glIndex == -1) {
3014 /* Our tests show that Windows returns D3D_OK in this situation, even with
3015 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3016 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3017 * as well for those lights.
3019 * TODO: Test how this affects rendering
3021 WARN("Too many concurrently active lights\n");
3022 return WINED3D_OK;
3025 /* i == lightInfo->glIndex */
3026 if(!This->isRecordingState) {
3027 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3032 return WINED3D_OK;
3035 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3037 PLIGHTINFOEL *lightInfo = NULL;
3038 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3039 struct list *e;
3040 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3041 TRACE("(%p) : for idx(%d)\n", This, Index);
3043 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3044 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3045 if(lightInfo->OriginalIndex == Index) break;
3046 lightInfo = NULL;
3049 if (lightInfo == NULL) {
3050 TRACE("Light enabled state requested but light not defined\n");
3051 return WINED3DERR_INVALIDCALL;
3053 /* true is 128 according to SetLightEnable */
3054 *pEnable = lightInfo->enabled ? 128 : 0;
3055 return WINED3D_OK;
3058 /*****
3059 * Get / Set Clip Planes
3060 *****/
3061 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3062 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3063 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3065 /* Validate Index */
3066 if (Index >= GL_LIMITS(clipplanes)) {
3067 TRACE("Application has requested clipplane this device doesn't support\n");
3068 return WINED3DERR_INVALIDCALL;
3071 This->updateStateBlock->changed.clipplane |= 1 << Index;
3073 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3074 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3075 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3076 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3077 TRACE("Application is setting old values over, nothing to do\n");
3078 return WINED3D_OK;
3081 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3082 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3083 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3084 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3086 /* Handle recording of state blocks */
3087 if (This->isRecordingState) {
3088 TRACE("Recording... not performing anything\n");
3089 return WINED3D_OK;
3092 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3094 return WINED3D_OK;
3097 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3098 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3099 TRACE("(%p) : for idx %d\n", This, Index);
3101 /* Validate Index */
3102 if (Index >= GL_LIMITS(clipplanes)) {
3103 TRACE("Application has requested clipplane this device doesn't support\n");
3104 return WINED3DERR_INVALIDCALL;
3107 pPlane[0] = This->stateBlock->clipplane[Index][0];
3108 pPlane[1] = This->stateBlock->clipplane[Index][1];
3109 pPlane[2] = This->stateBlock->clipplane[Index][2];
3110 pPlane[3] = This->stateBlock->clipplane[Index][3];
3111 return WINED3D_OK;
3114 /*****
3115 * Get / Set Clip Plane Status
3116 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3117 *****/
3118 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3120 FIXME("(%p) : stub\n", This);
3121 if (NULL == pClipStatus) {
3122 return WINED3DERR_INVALIDCALL;
3124 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3125 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3126 return WINED3D_OK;
3129 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3130 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3131 FIXME("(%p) : stub\n", This);
3132 if (NULL == pClipStatus) {
3133 return WINED3DERR_INVALIDCALL;
3135 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3136 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3137 return WINED3D_OK;
3140 /*****
3141 * Get / Set Material
3142 *****/
3143 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3146 This->updateStateBlock->changed.material = TRUE;
3147 This->updateStateBlock->material = *pMaterial;
3149 /* Handle recording of state blocks */
3150 if (This->isRecordingState) {
3151 TRACE("Recording... not performing anything\n");
3152 return WINED3D_OK;
3155 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3156 return WINED3D_OK;
3159 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3161 *pMaterial = This->updateStateBlock->material;
3162 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3163 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3164 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3165 pMaterial->Ambient.b, pMaterial->Ambient.a);
3166 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3167 pMaterial->Specular.b, pMaterial->Specular.a);
3168 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3169 pMaterial->Emissive.b, pMaterial->Emissive.a);
3170 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3172 return WINED3D_OK;
3175 /*****
3176 * Get / Set Indices
3177 *****/
3178 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DBuffer* pIndexData, WINED3DFORMAT fmt) {
3179 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3180 IWineD3DBuffer *oldIdxs;
3182 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3183 oldIdxs = This->updateStateBlock->pIndexData;
3185 This->updateStateBlock->changed.indices = TRUE;
3186 This->updateStateBlock->pIndexData = pIndexData;
3187 This->updateStateBlock->IndexFmt = fmt;
3189 /* Handle recording of state blocks */
3190 if (This->isRecordingState) {
3191 TRACE("Recording... not performing anything\n");
3192 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
3193 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
3194 return WINED3D_OK;
3197 if(oldIdxs != pIndexData) {
3198 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3199 if(pIndexData) {
3200 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
3201 IWineD3DBuffer_AddRef(pIndexData);
3203 if(oldIdxs) {
3204 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
3205 IWineD3DBuffer_Release(oldIdxs);
3209 return WINED3D_OK;
3212 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DBuffer** ppIndexData) {
3213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3215 *ppIndexData = This->stateBlock->pIndexData;
3217 /* up ref count on ppindexdata */
3218 if (*ppIndexData) {
3219 IWineD3DBuffer_AddRef(*ppIndexData);
3220 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3221 }else{
3222 TRACE("(%p) No index data set\n", This);
3224 TRACE("Returning %p\n", *ppIndexData);
3226 return WINED3D_OK;
3229 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3230 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3231 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3232 TRACE("(%p)->(%d)\n", This, BaseIndex);
3234 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3235 TRACE("Application is setting the old value over, nothing to do\n");
3236 return WINED3D_OK;
3239 This->updateStateBlock->baseVertexIndex = BaseIndex;
3241 if (This->isRecordingState) {
3242 TRACE("Recording... not performing anything\n");
3243 return WINED3D_OK;
3245 /* The base vertex index affects the stream sources */
3246 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3247 return WINED3D_OK;
3250 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3252 TRACE("(%p) : base_index %p\n", This, base_index);
3254 *base_index = This->stateBlock->baseVertexIndex;
3256 TRACE("Returning %u\n", *base_index);
3258 return WINED3D_OK;
3261 /*****
3262 * Get / Set Viewports
3263 *****/
3264 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3265 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3267 TRACE("(%p)\n", This);
3268 This->updateStateBlock->changed.viewport = TRUE;
3269 This->updateStateBlock->viewport = *pViewport;
3271 /* Handle recording of state blocks */
3272 if (This->isRecordingState) {
3273 TRACE("Recording... not performing anything\n");
3274 return WINED3D_OK;
3277 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3278 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3280 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3281 return WINED3D_OK;
3285 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3286 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3287 TRACE("(%p)\n", This);
3288 *pViewport = This->stateBlock->viewport;
3289 return WINED3D_OK;
3292 /*****
3293 * Get / Set Render States
3294 * TODO: Verify against dx9 definitions
3295 *****/
3296 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3299 DWORD oldValue = This->stateBlock->renderState[State];
3301 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3303 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3304 This->updateStateBlock->renderState[State] = Value;
3306 /* Handle recording of state blocks */
3307 if (This->isRecordingState) {
3308 TRACE("Recording... not performing anything\n");
3309 return WINED3D_OK;
3312 /* Compared here and not before the assignment to allow proper stateblock recording */
3313 if(Value == oldValue) {
3314 TRACE("Application is setting the old value over, nothing to do\n");
3315 } else {
3316 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3319 return WINED3D_OK;
3322 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3323 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3324 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3325 *pValue = This->stateBlock->renderState[State];
3326 return WINED3D_OK;
3329 /*****
3330 * Get / Set Sampler States
3331 * TODO: Verify against dx9 definitions
3332 *****/
3334 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3335 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3336 DWORD oldValue;
3338 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3339 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3341 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3342 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3345 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3346 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3347 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3350 * SetSampler is designed to allow for more than the standard up to 8 textures
3351 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3352 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3354 * http://developer.nvidia.com/object/General_FAQ.html#t6
3356 * There are two new settings for GForce
3357 * the sampler one:
3358 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3359 * and the texture one:
3360 * GL_MAX_TEXTURE_COORDS_ARB.
3361 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3362 ******************/
3364 oldValue = This->stateBlock->samplerState[Sampler][Type];
3365 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3366 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3368 /* Handle recording of state blocks */
3369 if (This->isRecordingState) {
3370 TRACE("Recording... not performing anything\n");
3371 return WINED3D_OK;
3374 if(oldValue == Value) {
3375 TRACE("Application is setting the old value over, nothing to do\n");
3376 return WINED3D_OK;
3379 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3381 return WINED3D_OK;
3384 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3387 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3388 This, Sampler, debug_d3dsamplerstate(Type), Type);
3390 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3391 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3394 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3395 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3396 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3398 *Value = This->stateBlock->samplerState[Sampler][Type];
3399 TRACE("(%p) : Returning %#x\n", This, *Value);
3401 return WINED3D_OK;
3404 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3405 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3407 This->updateStateBlock->changed.scissorRect = TRUE;
3408 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3409 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3410 return WINED3D_OK;
3412 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3414 if(This->isRecordingState) {
3415 TRACE("Recording... not performing anything\n");
3416 return WINED3D_OK;
3419 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3421 return WINED3D_OK;
3424 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3425 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3427 *pRect = This->updateStateBlock->scissorRect;
3428 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3429 return WINED3D_OK;
3432 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3433 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3434 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3436 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3438 This->updateStateBlock->vertexDecl = pDecl;
3439 This->updateStateBlock->changed.vertexDecl = TRUE;
3441 if (This->isRecordingState) {
3442 TRACE("Recording... not performing anything\n");
3443 return WINED3D_OK;
3444 } else if(pDecl == oldDecl) {
3445 /* Checked after the assignment to allow proper stateblock recording */
3446 TRACE("Application is setting the old declaration over, nothing to do\n");
3447 return WINED3D_OK;
3450 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3451 return WINED3D_OK;
3454 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3455 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3457 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3459 *ppDecl = This->stateBlock->vertexDecl;
3460 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3461 return WINED3D_OK;
3464 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3465 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3466 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3468 This->updateStateBlock->vertexShader = pShader;
3469 This->updateStateBlock->changed.vertexShader = TRUE;
3471 if (This->isRecordingState) {
3472 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3473 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3474 TRACE("Recording... not performing anything\n");
3475 return WINED3D_OK;
3476 } else if(oldShader == pShader) {
3477 /* Checked here to allow proper stateblock recording */
3478 TRACE("App is setting the old shader over, nothing to do\n");
3479 return WINED3D_OK;
3482 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3483 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3484 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3486 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3488 return WINED3D_OK;
3491 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3492 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3494 if (NULL == ppShader) {
3495 return WINED3DERR_INVALIDCALL;
3497 *ppShader = This->stateBlock->vertexShader;
3498 if( NULL != *ppShader)
3499 IWineD3DVertexShader_AddRef(*ppShader);
3501 TRACE("(%p) : returning %p\n", This, *ppShader);
3502 return WINED3D_OK;
3505 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3506 IWineD3DDevice *iface,
3507 UINT start,
3508 CONST BOOL *srcData,
3509 UINT count) {
3511 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3512 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3514 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3515 iface, srcData, start, count);
3517 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3519 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3520 for (i = 0; i < cnt; i++)
3521 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3523 for (i = start; i < cnt + start; ++i) {
3524 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3527 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3529 return WINED3D_OK;
3532 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3533 IWineD3DDevice *iface,
3534 UINT start,
3535 BOOL *dstData,
3536 UINT count) {
3538 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3539 int cnt = min(count, MAX_CONST_B - start);
3541 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3542 iface, dstData, start, count);
3544 if (dstData == NULL || cnt < 0)
3545 return WINED3DERR_INVALIDCALL;
3547 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3548 return WINED3D_OK;
3551 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3552 IWineD3DDevice *iface,
3553 UINT start,
3554 CONST int *srcData,
3555 UINT count) {
3557 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3558 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3560 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3561 iface, srcData, start, count);
3563 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3565 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3566 for (i = 0; i < cnt; i++)
3567 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3568 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3570 for (i = start; i < cnt + start; ++i) {
3571 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3574 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3576 return WINED3D_OK;
3579 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3580 IWineD3DDevice *iface,
3581 UINT start,
3582 int *dstData,
3583 UINT count) {
3585 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3586 int cnt = min(count, MAX_CONST_I - start);
3588 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3589 iface, dstData, start, count);
3591 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3592 return WINED3DERR_INVALIDCALL;
3594 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3595 return WINED3D_OK;
3598 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3599 IWineD3DDevice *iface,
3600 UINT start,
3601 CONST float *srcData,
3602 UINT count) {
3604 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3605 UINT i;
3607 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3608 iface, srcData, start, count);
3610 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3611 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3612 return WINED3DERR_INVALIDCALL;
3614 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3615 if(TRACE_ON(d3d)) {
3616 for (i = 0; i < count; i++)
3617 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3618 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3621 if (!This->isRecordingState)
3623 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3624 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3627 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3628 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3630 return WINED3D_OK;
3633 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3634 IWineD3DDevice *iface,
3635 UINT start,
3636 float *dstData,
3637 UINT count) {
3639 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3640 int cnt = min(count, This->d3d_vshader_constantF - start);
3642 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3643 iface, dstData, start, count);
3645 if (dstData == NULL || cnt < 0)
3646 return WINED3DERR_INVALIDCALL;
3648 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3649 return WINED3D_OK;
3652 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3653 DWORD i;
3654 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3656 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3660 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3661 int i = This->rev_tex_unit_map[unit];
3662 int j = This->texUnitMap[stage];
3664 This->texUnitMap[stage] = unit;
3665 if (i != -1 && i != stage) {
3666 This->texUnitMap[i] = -1;
3669 This->rev_tex_unit_map[unit] = stage;
3670 if (j != -1 && j != unit) {
3671 This->rev_tex_unit_map[j] = -1;
3675 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3676 int i;
3678 This->fixed_function_usage_map = 0;
3679 for (i = 0; i < MAX_TEXTURES; ++i) {
3680 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3681 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3682 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3683 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3684 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3685 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3686 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3687 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3689 if (color_op == WINED3DTOP_DISABLE) {
3690 /* Not used, and disable higher stages */
3691 break;
3694 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3695 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3696 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3697 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3698 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3699 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3700 This->fixed_function_usage_map |= (1 << i);
3703 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3704 This->fixed_function_usage_map |= (1 << (i + 1));
3709 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3710 unsigned int i, tex;
3711 WORD ffu_map;
3713 device_update_fixed_function_usage_map(This);
3714 ffu_map = This->fixed_function_usage_map;
3716 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3717 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3718 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3720 if (!(ffu_map & 1)) continue;
3722 if (This->texUnitMap[i] != i) {
3723 device_map_stage(This, i, i);
3724 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3725 markTextureStagesDirty(This, i);
3728 return;
3731 /* Now work out the mapping */
3732 tex = 0;
3733 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3735 if (!(ffu_map & 1)) continue;
3737 if (This->texUnitMap[i] != tex) {
3738 device_map_stage(This, i, tex);
3739 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3740 markTextureStagesDirty(This, i);
3743 ++tex;
3747 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3748 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3749 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3750 unsigned int i;
3752 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3753 if (sampler_type[i] && This->texUnitMap[i] != i)
3755 device_map_stage(This, i, i);
3756 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3757 if (i < MAX_TEXTURES) {
3758 markTextureStagesDirty(This, i);
3764 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3765 const DWORD *vshader_sampler_tokens, int unit)
3767 int current_mapping = This->rev_tex_unit_map[unit];
3769 if (current_mapping == -1) {
3770 /* Not currently used */
3771 return TRUE;
3774 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3775 /* Used by a fragment sampler */
3777 if (!pshader_sampler_tokens) {
3778 /* No pixel shader, check fixed function */
3779 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3782 /* Pixel shader, check the shader's sampler map */
3783 return !pshader_sampler_tokens[current_mapping];
3786 /* Used by a vertex sampler */
3787 return !vshader_sampler_tokens[current_mapping];
3790 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3791 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3792 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3793 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3794 int start = GL_LIMITS(combined_samplers) - 1;
3795 int i;
3797 if (ps) {
3798 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3800 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3801 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3802 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3805 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3806 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3807 if (vshader_sampler_type[i])
3809 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3811 /* Already mapped somewhere */
3812 continue;
3815 while (start >= 0) {
3816 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3818 device_map_stage(This, vsampler_idx, start);
3819 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3821 --start;
3822 break;
3825 --start;
3831 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3832 BOOL vs = use_vs(This->stateBlock);
3833 BOOL ps = use_ps(This->stateBlock);
3835 * Rules are:
3836 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3837 * that would be really messy and require shader recompilation
3838 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3839 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3841 if (ps) {
3842 device_map_psamplers(This);
3843 } else {
3844 device_map_fixed_function_samplers(This);
3847 if (vs) {
3848 device_map_vsamplers(This, ps);
3852 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3853 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3854 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3855 This->updateStateBlock->pixelShader = pShader;
3856 This->updateStateBlock->changed.pixelShader = TRUE;
3858 /* Handle recording of state blocks */
3859 if (This->isRecordingState) {
3860 TRACE("Recording... not performing anything\n");
3863 if (This->isRecordingState) {
3864 TRACE("Recording... not performing anything\n");
3865 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3866 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3867 return WINED3D_OK;
3870 if(pShader == oldShader) {
3871 TRACE("App is setting the old pixel shader over, nothing to do\n");
3872 return WINED3D_OK;
3875 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3876 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3878 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3879 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3881 return WINED3D_OK;
3884 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3885 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3887 if (NULL == ppShader) {
3888 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3889 return WINED3DERR_INVALIDCALL;
3892 *ppShader = This->stateBlock->pixelShader;
3893 if (NULL != *ppShader) {
3894 IWineD3DPixelShader_AddRef(*ppShader);
3896 TRACE("(%p) : returning %p\n", This, *ppShader);
3897 return WINED3D_OK;
3900 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3901 IWineD3DDevice *iface,
3902 UINT start,
3903 CONST BOOL *srcData,
3904 UINT count) {
3906 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3907 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3909 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3910 iface, srcData, start, count);
3912 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3914 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3915 for (i = 0; i < cnt; i++)
3916 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3918 for (i = start; i < cnt + start; ++i) {
3919 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3922 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3924 return WINED3D_OK;
3927 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3928 IWineD3DDevice *iface,
3929 UINT start,
3930 BOOL *dstData,
3931 UINT count) {
3933 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3934 int cnt = min(count, MAX_CONST_B - start);
3936 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3937 iface, dstData, start, count);
3939 if (dstData == NULL || cnt < 0)
3940 return WINED3DERR_INVALIDCALL;
3942 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3943 return WINED3D_OK;
3946 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3947 IWineD3DDevice *iface,
3948 UINT start,
3949 CONST int *srcData,
3950 UINT count) {
3952 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3953 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3955 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3956 iface, srcData, start, count);
3958 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3960 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3961 for (i = 0; i < cnt; i++)
3962 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3963 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3965 for (i = start; i < cnt + start; ++i) {
3966 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3969 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3971 return WINED3D_OK;
3974 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3975 IWineD3DDevice *iface,
3976 UINT start,
3977 int *dstData,
3978 UINT count) {
3980 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3981 int cnt = min(count, MAX_CONST_I - start);
3983 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3984 iface, dstData, start, count);
3986 if (dstData == NULL || cnt < 0)
3987 return WINED3DERR_INVALIDCALL;
3989 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3990 return WINED3D_OK;
3993 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3994 IWineD3DDevice *iface,
3995 UINT start,
3996 CONST float *srcData,
3997 UINT count) {
3999 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4000 UINT i;
4002 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4003 iface, srcData, start, count);
4005 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4006 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
4007 return WINED3DERR_INVALIDCALL;
4009 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4010 if(TRACE_ON(d3d)) {
4011 for (i = 0; i < count; i++)
4012 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4013 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4016 if (!This->isRecordingState)
4018 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
4019 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4022 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
4023 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
4025 return WINED3D_OK;
4028 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4029 IWineD3DDevice *iface,
4030 UINT start,
4031 float *dstData,
4032 UINT count) {
4034 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4035 int cnt = min(count, This->d3d_pshader_constantF - start);
4037 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4038 iface, dstData, start, count);
4040 if (dstData == NULL || cnt < 0)
4041 return WINED3DERR_INVALIDCALL;
4043 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4044 return WINED3D_OK;
4047 /* Context activation is done by the caller. */
4048 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4049 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4050 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
4051 DWORD DestFVF)
4053 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4054 unsigned int i;
4055 WINED3DVIEWPORT vp;
4056 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4057 BOOL doClip;
4058 DWORD numTextures;
4060 if (stream_info->elements[WINED3D_FFP_NORMAL].data)
4062 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4065 if (!stream_info->elements[WINED3D_FFP_POSITION].data)
4067 ERR("Source has no position mask\n");
4068 return WINED3DERR_INVALIDCALL;
4071 /* We might access VBOs from this code, so hold the lock */
4072 ENTER_GL();
4074 if (dest->resource.allocatedMemory == NULL) {
4075 buffer_get_sysmem(dest);
4078 /* Get a pointer into the destination vbo(create one if none exists) and
4079 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4081 if (!dest->buffer_object && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT))
4083 dest->flags |= WINED3D_BUFFER_CREATEBO;
4084 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
4087 if (dest->buffer_object)
4089 unsigned char extrabytes = 0;
4090 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4091 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4092 * this may write 4 extra bytes beyond the area that should be written
4094 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4095 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4096 if(!dest_conv_addr) {
4097 ERR("Out of memory\n");
4098 /* Continue without storing converted vertices */
4100 dest_conv = dest_conv_addr;
4103 /* Should I clip?
4104 * a) WINED3DRS_CLIPPING is enabled
4105 * b) WINED3DVOP_CLIP is passed
4107 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4108 static BOOL warned = FALSE;
4110 * The clipping code is not quite correct. Some things need
4111 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4112 * so disable clipping for now.
4113 * (The graphics in Half-Life are broken, and my processvertices
4114 * test crashes with IDirect3DDevice3)
4115 doClip = TRUE;
4117 doClip = FALSE;
4118 if(!warned) {
4119 warned = TRUE;
4120 FIXME("Clipping is broken and disabled for now\n");
4122 } else doClip = FALSE;
4123 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4125 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4126 WINED3DTS_VIEW,
4127 &view_mat);
4128 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4129 WINED3DTS_PROJECTION,
4130 &proj_mat);
4131 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4132 WINED3DTS_WORLDMATRIX(0),
4133 &world_mat);
4135 TRACE("View mat:\n");
4136 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);
4137 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);
4138 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);
4139 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);
4141 TRACE("Proj mat:\n");
4142 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);
4143 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);
4144 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);
4145 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);
4147 TRACE("World mat:\n");
4148 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);
4149 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);
4150 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);
4151 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);
4153 /* Get the viewport */
4154 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4155 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4156 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4158 multiply_matrix(&mat,&view_mat,&world_mat);
4159 multiply_matrix(&mat,&proj_mat,&mat);
4161 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4163 for (i = 0; i < dwCount; i+= 1) {
4164 unsigned int tex_index;
4166 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4167 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4168 /* The position first */
4169 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
4170 const float *p = (const float *)(element->data + i * element->stride);
4171 float x, y, z, rhw;
4172 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4174 /* Multiplication with world, view and projection matrix */
4175 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);
4176 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);
4177 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);
4178 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);
4180 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4182 /* WARNING: The following things are taken from d3d7 and were not yet checked
4183 * against d3d8 or d3d9!
4186 /* Clipping conditions: From msdn
4188 * A vertex is clipped if it does not match the following requirements
4189 * -rhw < x <= rhw
4190 * -rhw < y <= rhw
4191 * 0 < z <= rhw
4192 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4194 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4195 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4199 if( !doClip ||
4200 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4201 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4202 ( rhw > eps ) ) ) {
4204 /* "Normal" viewport transformation (not clipped)
4205 * 1) The values are divided by rhw
4206 * 2) The y axis is negative, so multiply it with -1
4207 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4208 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4209 * 4) Multiply x with Width/2 and add Width/2
4210 * 5) The same for the height
4211 * 6) Add the viewpoint X and Y to the 2D coordinates and
4212 * The minimum Z value to z
4213 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4215 * Well, basically it's simply a linear transformation into viewport
4216 * coordinates
4219 x /= rhw;
4220 y /= rhw;
4221 z /= rhw;
4223 y *= -1;
4225 x *= vp.Width / 2;
4226 y *= vp.Height / 2;
4227 z *= vp.MaxZ - vp.MinZ;
4229 x += vp.Width / 2 + vp.X;
4230 y += vp.Height / 2 + vp.Y;
4231 z += vp.MinZ;
4233 rhw = 1 / rhw;
4234 } else {
4235 /* That vertex got clipped
4236 * Contrary to OpenGL it is not dropped completely, it just
4237 * undergoes a different calculation.
4239 TRACE("Vertex got clipped\n");
4240 x += rhw;
4241 y += rhw;
4243 x /= 2;
4244 y /= 2;
4246 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4247 * outside of the main vertex buffer memory. That needs some more
4248 * investigation...
4252 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4255 ( (float *) dest_ptr)[0] = x;
4256 ( (float *) dest_ptr)[1] = y;
4257 ( (float *) dest_ptr)[2] = z;
4258 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4260 dest_ptr += 3 * sizeof(float);
4262 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4263 dest_ptr += sizeof(float);
4266 if(dest_conv) {
4267 float w = 1 / rhw;
4268 ( (float *) dest_conv)[0] = x * w;
4269 ( (float *) dest_conv)[1] = y * w;
4270 ( (float *) dest_conv)[2] = z * w;
4271 ( (float *) dest_conv)[3] = w;
4273 dest_conv += 3 * sizeof(float);
4275 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4276 dest_conv += sizeof(float);
4280 if (DestFVF & WINED3DFVF_PSIZE) {
4281 dest_ptr += sizeof(DWORD);
4282 if(dest_conv) dest_conv += sizeof(DWORD);
4284 if (DestFVF & WINED3DFVF_NORMAL) {
4285 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4286 const float *normal = (const float *)(element->data + i * element->stride);
4287 /* AFAIK this should go into the lighting information */
4288 FIXME("Didn't expect the destination to have a normal\n");
4289 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4290 if(dest_conv) {
4291 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4295 if (DestFVF & WINED3DFVF_DIFFUSE) {
4296 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4297 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4298 if(!color_d) {
4299 static BOOL warned = FALSE;
4301 if(!warned) {
4302 ERR("No diffuse color in source, but destination has one\n");
4303 warned = TRUE;
4306 *( (DWORD *) dest_ptr) = 0xffffffff;
4307 dest_ptr += sizeof(DWORD);
4309 if(dest_conv) {
4310 *( (DWORD *) dest_conv) = 0xffffffff;
4311 dest_conv += sizeof(DWORD);
4314 else {
4315 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4316 if(dest_conv) {
4317 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4318 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4319 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4320 dest_conv += sizeof(DWORD);
4325 if (DestFVF & WINED3DFVF_SPECULAR) {
4326 /* What's the color value in the feedback buffer? */
4327 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4328 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4329 if(!color_s) {
4330 static BOOL warned = FALSE;
4332 if(!warned) {
4333 ERR("No specular color in source, but destination has one\n");
4334 warned = TRUE;
4337 *( (DWORD *) dest_ptr) = 0xFF000000;
4338 dest_ptr += sizeof(DWORD);
4340 if(dest_conv) {
4341 *( (DWORD *) dest_conv) = 0xFF000000;
4342 dest_conv += sizeof(DWORD);
4345 else {
4346 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4347 if(dest_conv) {
4348 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4349 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4350 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4351 dest_conv += sizeof(DWORD);
4356 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4357 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4358 const float *tex_coord = (const float *)(element->data + i * element->stride);
4359 if(!tex_coord) {
4360 ERR("No source texture, but destination requests one\n");
4361 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4362 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4364 else {
4365 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4366 if(dest_conv) {
4367 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4373 if(dest_conv) {
4374 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4375 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4376 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4377 dwCount * get_flexible_vertex_size(DestFVF),
4378 dest_conv_addr));
4379 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4380 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4383 LEAVE_GL();
4385 return WINED3D_OK;
4387 #undef copy_and_next
4389 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4390 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4391 DWORD DestFVF)
4393 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4394 struct wined3d_stream_info stream_info;
4395 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4396 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4398 if(pVertexDecl) {
4399 ERR("Output vertex declaration not implemented yet\n");
4402 /* Need any context to write to the vbo. */
4403 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4405 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4406 * control the streamIsUP flag, thus restore it afterwards.
4408 This->stateBlock->streamIsUP = FALSE;
4409 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4410 This->stateBlock->streamIsUP = streamWasUP;
4412 if(vbo || SrcStartIndex) {
4413 unsigned int i;
4414 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4415 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4417 * Also get the start index in, but only loop over all elements if there's something to add at all.
4419 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4421 struct wined3d_stream_info_element *e = &stream_info.elements[i];
4422 if (e->buffer_object)
4424 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
4425 e->buffer_object = 0;
4426 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
4427 ENTER_GL();
4428 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4429 vb->buffer_object = 0;
4430 LEAVE_GL();
4432 if (e->data) e->data += e->stride * SrcStartIndex;
4436 return process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4437 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4440 /*****
4441 * Get / Set Texture Stage States
4442 * TODO: Verify against dx9 definitions
4443 *****/
4444 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4445 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4446 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4448 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4450 if (Stage >= MAX_TEXTURES) {
4451 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4452 return WINED3D_OK;
4455 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4456 This->updateStateBlock->textureState[Stage][Type] = Value;
4458 if (This->isRecordingState) {
4459 TRACE("Recording... not performing anything\n");
4460 return WINED3D_OK;
4463 /* Checked after the assignments to allow proper stateblock recording */
4464 if(oldValue == Value) {
4465 TRACE("App is setting the old value over, nothing to do\n");
4466 return WINED3D_OK;
4469 if(Stage > This->stateBlock->lowest_disabled_stage &&
4470 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4471 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4472 * Changes in other states are important on disabled stages too
4474 return WINED3D_OK;
4477 if(Type == WINED3DTSS_COLOROP) {
4478 unsigned int i;
4480 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4481 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4482 * they have to be disabled
4484 * The current stage is dirtified below.
4486 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4487 TRACE("Additionally dirtifying stage %u\n", i);
4488 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4490 This->stateBlock->lowest_disabled_stage = Stage;
4491 TRACE("New lowest disabled: %u\n", Stage);
4492 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4493 /* Previously disabled stage enabled. Stages above it may need enabling
4494 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4495 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4497 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4500 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4501 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4502 break;
4504 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4505 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4507 This->stateBlock->lowest_disabled_stage = i;
4508 TRACE("New lowest disabled: %u\n", i);
4512 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4514 return WINED3D_OK;
4517 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4518 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4519 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4520 *pValue = This->updateStateBlock->textureState[Stage][Type];
4521 return WINED3D_OK;
4524 /*****
4525 * Get / Set Texture
4526 *****/
4527 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4528 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4529 IWineD3DBaseTexture *oldTexture;
4531 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4533 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4534 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4537 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4538 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4539 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4542 oldTexture = This->updateStateBlock->textures[Stage];
4544 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4545 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
4547 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4548 return WINED3DERR_INVALIDCALL;
4551 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4552 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4554 This->updateStateBlock->changed.textures |= 1 << Stage;
4555 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4556 This->updateStateBlock->textures[Stage] = pTexture;
4558 /* Handle recording of state blocks */
4559 if (This->isRecordingState) {
4560 TRACE("Recording... not performing anything\n");
4561 return WINED3D_OK;
4564 if(oldTexture == pTexture) {
4565 TRACE("App is setting the same texture again, nothing to do\n");
4566 return WINED3D_OK;
4569 /** NOTE: MSDN says that setTexture increases the reference count,
4570 * and that the application must set the texture back to null (or have a leaky application),
4571 * This means we should pass the refcount up to the parent
4572 *******************************/
4573 if (NULL != This->updateStateBlock->textures[Stage]) {
4574 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4575 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4576 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4578 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4580 if (!oldTexture || dimensions != IWineD3DBaseTexture_GetTextureDimensions(oldTexture))
4582 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4585 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4586 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4587 * so the COLOROP and ALPHAOP have to be dirtified.
4589 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4590 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4592 if(bindCount == 1) {
4593 new->baseTexture.sampler = Stage;
4595 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4599 if (NULL != oldTexture) {
4600 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4601 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4603 IWineD3DBaseTexture_Release(oldTexture);
4604 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4605 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4606 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4609 if(bindCount && old->baseTexture.sampler == Stage) {
4610 int i;
4611 /* Have to do a search for the other sampler(s) where the texture is bound to
4612 * Shouldn't happen as long as apps bind a texture only to one stage
4614 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4615 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4616 if(This->updateStateBlock->textures[i] == oldTexture) {
4617 old->baseTexture.sampler = i;
4618 break;
4624 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4626 return WINED3D_OK;
4629 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4630 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4632 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4634 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4635 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4638 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4639 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4640 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4643 *ppTexture=This->stateBlock->textures[Stage];
4644 if (*ppTexture)
4645 IWineD3DBaseTexture_AddRef(*ppTexture);
4647 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4649 return WINED3D_OK;
4652 /*****
4653 * Get Back Buffer
4654 *****/
4655 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4656 IWineD3DSurface **ppBackBuffer) {
4657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4658 IWineD3DSwapChain *swapChain;
4659 HRESULT hr;
4661 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4663 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4664 if (hr == WINED3D_OK) {
4665 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4666 IWineD3DSwapChain_Release(swapChain);
4667 } else {
4668 *ppBackBuffer = NULL;
4670 return hr;
4673 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4675 WARN("(%p) : stub, calling idirect3d for now\n", This);
4676 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4679 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4681 IWineD3DSwapChain *swapChain;
4682 HRESULT hr;
4684 if(iSwapChain > 0) {
4685 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4686 if (hr == WINED3D_OK) {
4687 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4688 IWineD3DSwapChain_Release(swapChain);
4689 } else {
4690 FIXME("(%p) Error getting display mode\n", This);
4692 } else {
4693 /* Don't read the real display mode,
4694 but return the stored mode instead. X11 can't change the color
4695 depth, and some apps are pretty angry if they SetDisplayMode from
4696 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4698 Also don't relay to the swapchain because with ddraw it's possible
4699 that there isn't a swapchain at all */
4700 pMode->Width = This->ddraw_width;
4701 pMode->Height = This->ddraw_height;
4702 pMode->Format = This->ddraw_format;
4703 pMode->RefreshRate = 0;
4704 hr = WINED3D_OK;
4707 return hr;
4710 /*****
4711 * Stateblock related functions
4712 *****/
4714 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4715 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4716 IWineD3DStateBlock *stateblock;
4717 HRESULT hr;
4719 TRACE("(%p)\n", This);
4721 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4723 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4724 if (FAILED(hr)) return hr;
4726 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4727 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4728 This->isRecordingState = TRUE;
4730 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4732 return WINED3D_OK;
4735 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4736 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4737 unsigned int i, j;
4738 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4740 if (!This->isRecordingState) {
4741 WARN("(%p) not recording! returning error\n", This);
4742 *ppStateBlock = NULL;
4743 return WINED3DERR_INVALIDCALL;
4746 for (i = 0; i <= WINEHIGHEST_RENDER_STATE >> 5; ++i)
4748 DWORD map = object->changed.renderState[i];
4749 for (j = 0; map; map >>= 1, ++j)
4751 if (!(map & 1)) continue;
4753 object->contained_render_states[object->num_contained_render_states++] = (i << 5) | j;
4757 for (i = 0; i <= HIGHEST_TRANSFORMSTATE >> 5; ++i)
4759 DWORD map = object->changed.transform[i];
4760 for (j = 0; map; map >>= 1, ++j)
4762 if (!(map & 1)) continue;
4764 object->contained_transform_states[object->num_contained_transform_states++] = (i << 5) | j;
4767 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4768 if(object->changed.vertexShaderConstantsF[i]) {
4769 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4770 object->num_contained_vs_consts_f++;
4773 for(i = 0; i < MAX_CONST_I; i++) {
4774 if (object->changed.vertexShaderConstantsI & (1 << i))
4776 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4777 object->num_contained_vs_consts_i++;
4780 for(i = 0; i < MAX_CONST_B; i++) {
4781 if (object->changed.vertexShaderConstantsB & (1 << i))
4783 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4784 object->num_contained_vs_consts_b++;
4787 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
4789 if (object->changed.pixelShaderConstantsF[i])
4791 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
4792 ++object->num_contained_ps_consts_f;
4795 for(i = 0; i < MAX_CONST_I; i++) {
4796 if (object->changed.pixelShaderConstantsI & (1 << i))
4798 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4799 object->num_contained_ps_consts_i++;
4802 for(i = 0; i < MAX_CONST_B; i++) {
4803 if (object->changed.pixelShaderConstantsB & (1 << i))
4805 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4806 object->num_contained_ps_consts_b++;
4809 for(i = 0; i < MAX_TEXTURES; i++) {
4810 DWORD map = object->changed.textureState[i];
4812 for(j = 0; map; map >>= 1, ++j)
4814 if (!(map & 1)) continue;
4816 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4817 object->contained_tss_states[object->num_contained_tss_states].state = j;
4818 ++object->num_contained_tss_states;
4821 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4822 DWORD map = object->changed.samplerState[i];
4824 for (j = 0; map; map >>= 1, ++j)
4826 if (!(map & 1)) continue;
4828 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4829 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4830 ++object->num_contained_sampler_states;
4834 *ppStateBlock = (IWineD3DStateBlock*) object;
4835 This->isRecordingState = FALSE;
4836 This->updateStateBlock = This->stateBlock;
4837 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4838 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4839 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4840 return WINED3D_OK;
4843 /*****
4844 * Scene related functions
4845 *****/
4846 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4847 /* At the moment we have no need for any functionality at the beginning
4848 of a scene */
4849 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4850 TRACE("(%p)\n", This);
4852 if(This->inScene) {
4853 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4854 return WINED3DERR_INVALIDCALL;
4856 This->inScene = TRUE;
4857 return WINED3D_OK;
4860 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4861 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4862 TRACE("(%p)\n", This);
4864 if(!This->inScene) {
4865 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4866 return WINED3DERR_INVALIDCALL;
4869 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4870 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4871 glFlush();
4872 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4873 * fails
4876 This->inScene = FALSE;
4877 return WINED3D_OK;
4880 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4881 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4882 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4883 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4884 IWineD3DSwapChain *swapChain = NULL;
4885 int i;
4886 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4888 TRACE("(%p) Presenting the frame\n", This);
4890 for(i = 0 ; i < swapchains ; i ++) {
4892 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4893 TRACE("presentinng chain %d, %p\n", i, swapChain);
4894 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4895 IWineD3DSwapChain_Release(swapChain);
4898 return WINED3D_OK;
4901 /* Not called from the VTable (internal subroutine) */
4902 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4903 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4904 float Z, DWORD Stencil) {
4905 GLbitfield glMask = 0;
4906 unsigned int i;
4907 WINED3DRECT curRect;
4908 RECT vp_rect;
4909 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4910 UINT drawable_width, drawable_height;
4911 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4912 IWineD3DSwapChainImpl *swapchain = NULL;
4914 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4915 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4916 * for the cleared parts, and the untouched parts.
4918 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4919 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4920 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4921 * checking all this if the dest surface is in the drawable anyway.
4923 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4924 while(1) {
4925 if(vp->X != 0 || vp->Y != 0 ||
4926 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4927 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4928 break;
4930 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4931 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4932 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4933 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4934 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4935 break;
4937 if(Count > 0 && pRects && (
4938 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4939 pRects[0].x2 < target->currentDesc.Width ||
4940 pRects[0].y2 < target->currentDesc.Height)) {
4941 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4942 break;
4944 break;
4948 target->get_drawable_size(target, &drawable_width, &drawable_height);
4950 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
4951 ENTER_GL();
4953 /* Only set the values up once, as they are not changing */
4954 if (Flags & WINED3DCLEAR_STENCIL) {
4955 glClearStencil(Stencil);
4956 checkGLcall("glClearStencil");
4957 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4958 glStencilMask(0xFFFFFFFF);
4961 if (Flags & WINED3DCLEAR_ZBUFFER) {
4962 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4963 glDepthMask(GL_TRUE);
4964 glClearDepth(Z);
4965 checkGLcall("glClearDepth");
4966 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4967 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4969 if (vp->X != 0 || vp->Y != 0 ||
4970 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4971 surface_load_ds_location(This->stencilBufferTarget, location);
4973 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4974 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4975 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4976 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4977 surface_load_ds_location(This->stencilBufferTarget, location);
4979 else if (Count > 0 && pRects && (
4980 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4981 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4982 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4983 surface_load_ds_location(This->stencilBufferTarget, location);
4987 if (Flags & WINED3DCLEAR_TARGET) {
4988 TRACE("Clearing screen with glClear to color %x\n", Color);
4989 glClearColor(D3DCOLOR_R(Color),
4990 D3DCOLOR_G(Color),
4991 D3DCOLOR_B(Color),
4992 D3DCOLOR_A(Color));
4993 checkGLcall("glClearColor");
4995 /* Clear ALL colors! */
4996 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4997 glMask = glMask | GL_COLOR_BUFFER_BIT;
5000 vp_rect.left = vp->X;
5001 vp_rect.top = vp->Y;
5002 vp_rect.right = vp->X + vp->Width;
5003 vp_rect.bottom = vp->Y + vp->Height;
5004 if (!(Count > 0 && pRects)) {
5005 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5006 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5008 if(This->render_offscreen) {
5009 glScissor(vp_rect.left, vp_rect.top,
5010 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5011 } else {
5012 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5013 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5015 checkGLcall("glScissor");
5016 glClear(glMask);
5017 checkGLcall("glClear");
5018 } else {
5019 /* Now process each rect in turn */
5020 for (i = 0; i < Count; i++) {
5021 /* Note gl uses lower left, width/height */
5022 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5023 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5024 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5026 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5027 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5028 curRect.x1, (target->currentDesc.Height - curRect.y2),
5029 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5031 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5032 * The rectangle is not cleared, no error is returned, but further rectanlges are
5033 * still cleared if they are valid
5035 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5036 TRACE("Rectangle with negative dimensions, ignoring\n");
5037 continue;
5040 if(This->render_offscreen) {
5041 glScissor(curRect.x1, curRect.y1,
5042 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5043 } else {
5044 glScissor(curRect.x1, drawable_height - curRect.y2,
5045 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5047 checkGLcall("glScissor");
5049 glClear(glMask);
5050 checkGLcall("glClear");
5054 /* Restore the old values (why..?) */
5055 if (Flags & WINED3DCLEAR_STENCIL) {
5056 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5058 if (Flags & WINED3DCLEAR_TARGET) {
5059 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5060 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5061 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5062 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5063 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5065 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5066 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5068 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5070 if (Flags & WINED3DCLEAR_ZBUFFER) {
5071 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5072 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5073 surface_modify_ds_location(This->stencilBufferTarget, location);
5076 LEAVE_GL();
5078 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5079 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5080 glFlush();
5082 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5085 return WINED3D_OK;
5088 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5089 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5090 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5091 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5093 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5094 Count, pRects, Flags, Color, Z, Stencil);
5096 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5097 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5098 /* TODO: What about depth stencil buffers without stencil bits? */
5099 return WINED3DERR_INVALIDCALL;
5102 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5105 /*****
5106 * Drawing functions
5107 *****/
5109 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
5110 WINED3DPRIMITIVETYPE primitive_type)
5112 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5114 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
5116 This->updateStateBlock->changed.primitive_type = TRUE;
5117 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
5120 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
5121 WINED3DPRIMITIVETYPE *primitive_type)
5123 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5125 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
5127 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
5129 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
5132 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
5134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5136 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
5138 if(!This->stateBlock->vertexDecl) {
5139 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5140 return WINED3DERR_INVALIDCALL;
5143 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5144 if(This->stateBlock->streamIsUP) {
5145 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5146 This->stateBlock->streamIsUP = FALSE;
5149 if(This->stateBlock->loadBaseVertexIndex != 0) {
5150 This->stateBlock->loadBaseVertexIndex = 0;
5151 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5153 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5154 drawPrimitive(iface, vertex_count, 0/* NumVertices */, StartVertex /* start_idx */,
5155 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5156 return WINED3D_OK;
5159 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5160 UINT minIndex, UINT NumVertices, UINT startIndex, UINT index_count)
5162 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5163 UINT idxStride = 2;
5164 IWineD3DBuffer *pIB;
5165 GLuint vbo;
5167 pIB = This->stateBlock->pIndexData;
5168 if (!pIB) {
5169 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5170 * without an index buffer set. (The first time at least...)
5171 * D3D8 simply dies, but I doubt it can do much harm to return
5172 * D3DERR_INVALIDCALL there as well. */
5173 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5174 return WINED3DERR_INVALIDCALL;
5177 if(!This->stateBlock->vertexDecl) {
5178 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5179 return WINED3DERR_INVALIDCALL;
5182 if(This->stateBlock->streamIsUP) {
5183 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5184 This->stateBlock->streamIsUP = FALSE;
5186 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
5188 TRACE("(%p) : min %u, vertex count %u, startIdx %u, index count %u\n",
5189 This, minIndex, NumVertices, startIndex, index_count);
5191 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
5192 idxStride = 2;
5193 } else {
5194 idxStride = 4;
5197 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5198 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5199 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5202 drawPrimitive(iface, index_count, NumVertices, startIndex, idxStride,
5203 vbo ? NULL : ((struct wined3d_buffer *) pIB)->resource.allocatedMemory, minIndex);
5205 return WINED3D_OK;
5208 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
5209 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5212 IWineD3DBuffer *vb;
5214 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
5215 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
5217 if(!This->stateBlock->vertexDecl) {
5218 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5219 return WINED3DERR_INVALIDCALL;
5222 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5223 vb = This->stateBlock->streamSource[0];
5224 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5225 if (vb) IWineD3DBuffer_Release(vb);
5226 This->stateBlock->streamOffset[0] = 0;
5227 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5228 This->stateBlock->streamIsUP = TRUE;
5229 This->stateBlock->loadBaseVertexIndex = 0;
5231 /* TODO: Only mark dirty if drawing from a different UP address */
5232 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5234 drawPrimitive(iface, vertex_count, 0 /* NumVertices */, 0 /* start_idx */,
5235 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5237 /* MSDN specifies stream zero settings must be set to NULL */
5238 This->stateBlock->streamStride[0] = 0;
5239 This->stateBlock->streamSource[0] = NULL;
5241 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5242 * the new stream sources or use UP drawing again
5244 return WINED3D_OK;
5247 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, UINT MinVertexIndex,
5248 UINT NumVertices, UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
5249 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5251 int idxStride;
5252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5253 IWineD3DBuffer *vb;
5254 IWineD3DBuffer *ib;
5256 TRACE("(%p) : MinVtxIdx %u, NumVIdx %u, index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u\n",
5257 This, MinVertexIndex, NumVertices, index_count, pIndexData,
5258 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5260 if(!This->stateBlock->vertexDecl) {
5261 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5262 return WINED3DERR_INVALIDCALL;
5265 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
5266 idxStride = 2;
5267 } else {
5268 idxStride = 4;
5271 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5272 vb = This->stateBlock->streamSource[0];
5273 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5274 if (vb) IWineD3DBuffer_Release(vb);
5275 This->stateBlock->streamIsUP = TRUE;
5276 This->stateBlock->streamOffset[0] = 0;
5277 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5279 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5280 This->stateBlock->baseVertexIndex = 0;
5281 This->stateBlock->loadBaseVertexIndex = 0;
5282 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5283 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5284 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5286 drawPrimitive(iface, index_count, NumVertices, 0 /* start_idx */,
5287 idxStride, pIndexData, MinVertexIndex);
5289 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5290 This->stateBlock->streamSource[0] = NULL;
5291 This->stateBlock->streamStride[0] = 0;
5292 ib = This->stateBlock->pIndexData;
5293 if(ib) {
5294 IWineD3DBuffer_Release(ib);
5295 This->stateBlock->pIndexData = NULL;
5297 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5298 * SetStreamSource to specify a vertex buffer
5301 return WINED3D_OK;
5304 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5305 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
5307 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5309 /* Mark the state dirty until we have nicer tracking
5310 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5311 * that value.
5313 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5314 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5315 This->stateBlock->baseVertexIndex = 0;
5316 This->up_strided = DrawPrimStrideData;
5317 drawPrimitive(iface, vertex_count, 0, 0, 0, NULL, 0);
5318 This->up_strided = NULL;
5319 return WINED3D_OK;
5322 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5323 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
5324 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
5326 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5327 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5329 /* Mark the state dirty until we have nicer tracking
5330 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5331 * that value.
5333 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5334 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5335 This->stateBlock->streamIsUP = TRUE;
5336 This->stateBlock->baseVertexIndex = 0;
5337 This->up_strided = DrawPrimStrideData;
5338 drawPrimitive(iface, vertex_count, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData, 0 /* minindex */);
5339 This->up_strided = NULL;
5340 return WINED3D_OK;
5343 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5344 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5345 * not callable by the app directly no parameter validation checks are needed here.
5347 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5348 WINED3DLOCKED_BOX src;
5349 WINED3DLOCKED_BOX dst;
5350 HRESULT hr;
5351 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5353 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5354 * dirtification to improve loading performance.
5356 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5357 if(FAILED(hr)) return hr;
5358 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5359 if(FAILED(hr)) {
5360 IWineD3DVolume_UnlockBox(pSourceVolume);
5361 return hr;
5364 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5366 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5367 if(FAILED(hr)) {
5368 IWineD3DVolume_UnlockBox(pSourceVolume);
5369 } else {
5370 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5372 return hr;
5375 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5376 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5377 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5378 HRESULT hr = WINED3D_OK;
5379 WINED3DRESOURCETYPE sourceType;
5380 WINED3DRESOURCETYPE destinationType;
5381 int i ,levels;
5383 /* TODO: think about moving the code into IWineD3DBaseTexture */
5385 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5387 /* verify that the source and destination textures aren't NULL */
5388 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5389 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5390 This, pSourceTexture, pDestinationTexture);
5391 hr = WINED3DERR_INVALIDCALL;
5394 if (pSourceTexture == pDestinationTexture) {
5395 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5396 This, pSourceTexture, pDestinationTexture);
5397 hr = WINED3DERR_INVALIDCALL;
5399 /* Verify that the source and destination textures are the same type */
5400 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5401 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5403 if (sourceType != destinationType) {
5404 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5405 This);
5406 hr = WINED3DERR_INVALIDCALL;
5409 /* check that both textures have the identical numbers of levels */
5410 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5411 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5412 hr = WINED3DERR_INVALIDCALL;
5415 if (WINED3D_OK == hr) {
5416 IWineD3DBaseTextureImpl *pDestImpl = (IWineD3DBaseTextureImpl *) pDestinationTexture;
5418 /* Make sure that the destination texture is loaded */
5419 pDestImpl->baseTexture.internal_preload(pDestinationTexture, SRGB_RGB);
5421 /* Update every surface level of the texture */
5422 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5424 switch (sourceType) {
5425 case WINED3DRTYPE_TEXTURE:
5427 IWineD3DSurface *srcSurface;
5428 IWineD3DSurface *destSurface;
5430 for (i = 0 ; i < levels ; ++i) {
5431 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5432 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5433 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5434 IWineD3DSurface_Release(srcSurface);
5435 IWineD3DSurface_Release(destSurface);
5436 if (WINED3D_OK != hr) {
5437 WARN("(%p) : Call to update surface failed\n", This);
5438 return hr;
5442 break;
5443 case WINED3DRTYPE_CUBETEXTURE:
5445 IWineD3DSurface *srcSurface;
5446 IWineD3DSurface *destSurface;
5447 WINED3DCUBEMAP_FACES faceType;
5449 for (i = 0 ; i < levels ; ++i) {
5450 /* Update each cube face */
5451 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5452 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5453 if (WINED3D_OK != hr) {
5454 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5455 } else {
5456 TRACE("Got srcSurface %p\n", srcSurface);
5458 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5459 if (WINED3D_OK != hr) {
5460 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5461 } else {
5462 TRACE("Got desrSurface %p\n", destSurface);
5464 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5465 IWineD3DSurface_Release(srcSurface);
5466 IWineD3DSurface_Release(destSurface);
5467 if (WINED3D_OK != hr) {
5468 WARN("(%p) : Call to update surface failed\n", This);
5469 return hr;
5474 break;
5476 case WINED3DRTYPE_VOLUMETEXTURE:
5478 IWineD3DVolume *srcVolume = NULL;
5479 IWineD3DVolume *destVolume = NULL;
5481 for (i = 0 ; i < levels ; ++i) {
5482 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5483 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5484 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5485 IWineD3DVolume_Release(srcVolume);
5486 IWineD3DVolume_Release(destVolume);
5487 if (WINED3D_OK != hr) {
5488 WARN("(%p) : Call to update volume failed\n", This);
5489 return hr;
5493 break;
5495 default:
5496 FIXME("(%p) : Unsupported source and destination type\n", This);
5497 hr = WINED3DERR_INVALIDCALL;
5501 return hr;
5504 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5505 IWineD3DSwapChain *swapChain;
5506 HRESULT hr;
5507 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5508 if(hr == WINED3D_OK) {
5509 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5510 IWineD3DSwapChain_Release(swapChain);
5512 return hr;
5515 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5517 IWineD3DBaseTextureImpl *texture;
5518 DWORD i;
5520 TRACE("(%p) : %p\n", This, pNumPasses);
5522 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5523 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5524 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5525 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5527 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5528 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5529 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5532 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5533 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5535 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5536 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5537 return E_FAIL;
5539 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5540 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5541 return E_FAIL;
5543 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5544 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5545 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5546 return E_FAIL;
5550 /* return a sensible default */
5551 *pNumPasses = 1;
5553 TRACE("returning D3D_OK\n");
5554 return WINED3D_OK;
5557 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5559 int i;
5561 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5562 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5563 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8
5564 || texture->resource.format_desc->format == WINED3DFMT_A8P8))
5566 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5571 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5572 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5573 int j;
5574 UINT NewSize;
5575 PALETTEENTRY **palettes;
5577 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5579 if (PaletteNumber >= MAX_PALETTES) {
5580 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5581 return WINED3DERR_INVALIDCALL;
5584 if (PaletteNumber >= This->NumberOfPalettes) {
5585 NewSize = This->NumberOfPalettes;
5586 do {
5587 NewSize *= 2;
5588 } while(PaletteNumber >= NewSize);
5589 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5590 if (!palettes) {
5591 ERR("Out of memory!\n");
5592 return E_OUTOFMEMORY;
5594 This->palettes = palettes;
5595 This->NumberOfPalettes = NewSize;
5598 if (!This->palettes[PaletteNumber]) {
5599 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5600 if (!This->palettes[PaletteNumber]) {
5601 ERR("Out of memory!\n");
5602 return E_OUTOFMEMORY;
5606 for (j = 0; j < 256; ++j) {
5607 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5608 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5609 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5610 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5612 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5613 TRACE("(%p) : returning\n", This);
5614 return WINED3D_OK;
5617 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5618 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5619 int j;
5620 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5621 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5622 /* What happens in such situation isn't documented; Native seems to silently abort
5623 on such conditions. Return Invalid Call. */
5624 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5625 return WINED3DERR_INVALIDCALL;
5627 for (j = 0; j < 256; ++j) {
5628 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5629 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5630 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5631 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5633 TRACE("(%p) : returning\n", This);
5634 return WINED3D_OK;
5637 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5638 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5639 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5640 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5641 (tested with reference rasterizer). Return Invalid Call. */
5642 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5643 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5644 return WINED3DERR_INVALIDCALL;
5646 /*TODO: stateblocks */
5647 if (This->currentPalette != PaletteNumber) {
5648 This->currentPalette = PaletteNumber;
5649 dirtify_p8_texture_samplers(This);
5651 TRACE("(%p) : returning\n", This);
5652 return WINED3D_OK;
5655 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5656 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5657 if (PaletteNumber == NULL) {
5658 WARN("(%p) : returning Invalid Call\n", This);
5659 return WINED3DERR_INVALIDCALL;
5661 /*TODO: stateblocks */
5662 *PaletteNumber = This->currentPalette;
5663 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5664 return WINED3D_OK;
5667 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5668 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5669 static BOOL warned;
5670 if (!warned)
5672 FIXME("(%p) : stub\n", This);
5673 warned = TRUE;
5676 This->softwareVertexProcessing = bSoftware;
5677 return WINED3D_OK;
5681 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5682 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5683 static BOOL warned;
5684 if (!warned)
5686 FIXME("(%p) : stub\n", This);
5687 warned = TRUE;
5689 return This->softwareVertexProcessing;
5693 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5695 IWineD3DSwapChain *swapChain;
5696 HRESULT hr;
5698 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5700 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5701 if(hr == WINED3D_OK){
5702 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5703 IWineD3DSwapChain_Release(swapChain);
5704 }else{
5705 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5707 return hr;
5711 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5712 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5713 static BOOL warned;
5714 if(nSegments != 0.0f) {
5715 if (!warned)
5717 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5718 warned = TRUE;
5721 return WINED3D_OK;
5724 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5726 static BOOL warned;
5727 if (!warned)
5729 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5730 warned = TRUE;
5732 return 0.0f;
5735 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5736 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5737 /** TODO: remove casts to IWineD3DSurfaceImpl
5738 * NOTE: move code to surface to accomplish this
5739 ****************************************/
5740 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5741 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)pDestinationSurface;
5742 int srcWidth, srcHeight;
5743 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5744 WINED3DFORMAT destFormat, srcFormat;
5745 UINT destSize;
5746 int srcLeft, destLeft, destTop;
5747 WINED3DPOOL srcPool, destPool;
5748 int offset = 0;
5749 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5750 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
5751 GLenum dummy;
5752 int sampler;
5753 int bpp;
5754 CONVERT_TYPES convert = NO_CONVERSION;
5756 WINED3DSURFACE_DESC winedesc;
5758 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5760 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5761 srcSurfaceWidth = winedesc.width;
5762 srcSurfaceHeight = winedesc.height;
5763 srcPool = winedesc.pool;
5764 srcFormat = winedesc.format;
5766 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5767 destSurfaceWidth = winedesc.width;
5768 destSurfaceHeight = winedesc.height;
5769 destPool = winedesc.pool;
5770 destFormat = winedesc.format;
5771 destSize = winedesc.size;
5773 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5774 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5775 return WINED3DERR_INVALIDCALL;
5778 /* This call loads the opengl surface directly, instead of copying the surface to the
5779 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5780 * copy in sysmem and use regular surface loading.
5782 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5783 if(convert != NO_CONVERSION) {
5784 return IWineD3DSurface_BltFast(pDestinationSurface,
5785 pDestPoint ? pDestPoint->x : 0,
5786 pDestPoint ? pDestPoint->y : 0,
5787 pSourceSurface, pSourceRect, 0);
5790 if (destFormat == WINED3DFMT_UNKNOWN) {
5791 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5792 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5794 /* Get the update surface description */
5795 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5798 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5800 ENTER_GL();
5801 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5802 checkGLcall("glActiveTextureARB");
5803 LEAVE_GL();
5805 /* Make sure the surface is loaded and up to date */
5806 surface_internal_preload(pDestinationSurface, SRGB_RGB);
5807 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5809 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
5810 dst_format_desc = dst_impl->resource.format_desc;
5812 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5813 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5814 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5815 srcLeft = pSourceRect ? pSourceRect->left : 0;
5816 destLeft = pDestPoint ? pDestPoint->x : 0;
5817 destTop = pDestPoint ? pDestPoint->y : 0;
5820 /* This function doesn't support compressed textures
5821 the pitch is just bytesPerPixel * width */
5822 if(srcWidth != srcSurfaceWidth || srcLeft ){
5823 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
5824 offset += srcLeft * src_format_desc->byte_count;
5825 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5827 /* TODO DXT formats */
5829 if(pSourceRect != NULL && pSourceRect->top != 0){
5830 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
5832 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5833 This, dst_impl->texture_level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
5834 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5836 /* Sanity check */
5837 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5839 /* need to lock the surface to get the data */
5840 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5843 ENTER_GL();
5845 /* TODO: Cube and volume support */
5846 if(rowoffset != 0){
5847 /* not a whole row so we have to do it a line at a time */
5848 int j;
5850 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5851 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5853 for (j = destTop; j < (srcHeight + destTop); ++j)
5855 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, j,
5856 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
5857 data += rowoffset;
5860 } else { /* Full width, so just write out the whole texture */
5861 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5863 if (dst_format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
5865 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth)
5867 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across. */
5868 FIXME("Updating part of a compressed texture is not supported.\n");
5870 if (destFormat != srcFormat)
5872 FIXME("Updating mixed format compressed textures is not supported.\n");
5874 else
5876 GL_EXTCALL(glCompressedTexImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5877 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
5880 else
5882 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, destTop,
5883 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
5886 checkGLcall("glTexSubImage2D");
5888 LEAVE_GL();
5890 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5891 sampler = This->rev_tex_unit_map[0];
5892 if (sampler != -1) {
5893 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5896 return WINED3D_OK;
5899 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5900 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5901 struct WineD3DRectPatch *patch;
5902 GLenum old_primitive_type;
5903 unsigned int i;
5904 struct list *e;
5905 BOOL found;
5906 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5908 if(!(Handle || pRectPatchInfo)) {
5909 /* TODO: Write a test for the return value, thus the FIXME */
5910 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5911 return WINED3DERR_INVALIDCALL;
5914 if(Handle) {
5915 i = PATCHMAP_HASHFUNC(Handle);
5916 found = FALSE;
5917 LIST_FOR_EACH(e, &This->patches[i]) {
5918 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5919 if(patch->Handle == Handle) {
5920 found = TRUE;
5921 break;
5925 if(!found) {
5926 TRACE("Patch does not exist. Creating a new one\n");
5927 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5928 patch->Handle = Handle;
5929 list_add_head(&This->patches[i], &patch->entry);
5930 } else {
5931 TRACE("Found existing patch %p\n", patch);
5933 } else {
5934 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5935 * attributes we have to tesselate, read back, and draw. This needs a patch
5936 * management structure instance. Create one.
5938 * A possible improvement is to check if a vertex shader is used, and if not directly
5939 * draw the patch.
5941 FIXME("Drawing an uncached patch. This is slow\n");
5942 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5945 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5946 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5947 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5948 HRESULT hr;
5949 TRACE("Tesselation density or patch info changed, retesselating\n");
5951 if(pRectPatchInfo) {
5952 patch->RectPatchInfo = *pRectPatchInfo;
5954 patch->numSegs[0] = pNumSegs[0];
5955 patch->numSegs[1] = pNumSegs[1];
5956 patch->numSegs[2] = pNumSegs[2];
5957 patch->numSegs[3] = pNumSegs[3];
5959 hr = tesselate_rectpatch(This, patch);
5960 if(FAILED(hr)) {
5961 WARN("Patch tesselation failed\n");
5963 /* Do not release the handle to store the params of the patch */
5964 if(!Handle) {
5965 HeapFree(GetProcessHeap(), 0, patch);
5967 return hr;
5971 This->currentPatch = patch;
5972 old_primitive_type = This->stateBlock->gl_primitive_type;
5973 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5974 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5975 This->stateBlock->gl_primitive_type = old_primitive_type;
5976 This->currentPatch = NULL;
5978 /* Destroy uncached patches */
5979 if(!Handle) {
5980 HeapFree(GetProcessHeap(), 0, patch->mem);
5981 HeapFree(GetProcessHeap(), 0, patch);
5983 return WINED3D_OK;
5986 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5987 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5988 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5989 FIXME("(%p) : Stub\n", This);
5990 return WINED3D_OK;
5993 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5994 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5995 int i;
5996 struct WineD3DRectPatch *patch;
5997 struct list *e;
5998 TRACE("(%p) Handle(%d)\n", This, Handle);
6000 i = PATCHMAP_HASHFUNC(Handle);
6001 LIST_FOR_EACH(e, &This->patches[i]) {
6002 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6003 if(patch->Handle == Handle) {
6004 TRACE("Deleting patch %p\n", patch);
6005 list_remove(&patch->entry);
6006 HeapFree(GetProcessHeap(), 0, patch->mem);
6007 HeapFree(GetProcessHeap(), 0, patch);
6008 return WINED3D_OK;
6012 /* TODO: Write a test for the return value */
6013 FIXME("Attempt to destroy nonexistent patch\n");
6014 return WINED3DERR_INVALIDCALL;
6017 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6018 HRESULT hr;
6019 IWineD3DSwapChain *swapchain;
6021 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6022 if (SUCCEEDED(hr)) {
6023 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6024 return swapchain;
6027 return NULL;
6030 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
6031 const WINED3DRECT *rect, const float color[4])
6033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6034 IWineD3DSwapChain *swapchain;
6036 swapchain = get_swapchain(surface);
6037 if (swapchain) {
6038 GLenum buffer;
6040 TRACE("Surface %p is onscreen\n", surface);
6042 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6043 ENTER_GL();
6044 context_bind_fbo(This->activeContext, GL_FRAMEBUFFER_EXT, NULL);
6045 buffer = surface_get_gl_buffer(surface, swapchain);
6046 glDrawBuffer(buffer);
6047 checkGLcall("glDrawBuffer()");
6048 } else {
6049 TRACE("Surface %p is offscreen\n", surface);
6051 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6052 ENTER_GL();
6053 context_bind_fbo(This->activeContext, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6054 context_attach_surface_fbo(This->activeContext, GL_FRAMEBUFFER_EXT, 0, surface);
6055 context_attach_depth_stencil_fbo(This->activeContext, GL_FRAMEBUFFER_EXT, NULL, FALSE);
6058 if (rect) {
6059 glEnable(GL_SCISSOR_TEST);
6060 if(!swapchain) {
6061 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6062 } else {
6063 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6064 rect->x2 - rect->x1, rect->y2 - rect->y1);
6066 checkGLcall("glScissor");
6067 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6068 } else {
6069 glDisable(GL_SCISSOR_TEST);
6071 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6073 glDisable(GL_BLEND);
6074 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6076 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6077 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6079 glClearColor(color[0], color[1], color[2], color[3]);
6080 glClear(GL_COLOR_BUFFER_BIT);
6081 checkGLcall("glClear");
6083 if (This->activeContext->current_fbo) {
6084 context_bind_fbo(This->activeContext, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6085 } else {
6086 context_bind_fbo(This->activeContext, GL_FRAMEBUFFER_EXT, NULL);
6089 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6090 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6091 glDrawBuffer(GL_BACK);
6092 checkGLcall("glDrawBuffer()");
6095 LEAVE_GL();
6098 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6099 unsigned int r, g, b, a;
6100 DWORD ret;
6102 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6103 destfmt == WINED3DFMT_R8G8B8)
6104 return color;
6106 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6108 a = (color & 0xff000000) >> 24;
6109 r = (color & 0x00ff0000) >> 16;
6110 g = (color & 0x0000ff00) >> 8;
6111 b = (color & 0x000000ff) >> 0;
6113 switch(destfmt)
6115 case WINED3DFMT_R5G6B5:
6116 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6117 r = (r * 32) / 256;
6118 g = (g * 64) / 256;
6119 b = (b * 32) / 256;
6120 ret = r << 11;
6121 ret |= g << 5;
6122 ret |= b;
6123 TRACE("Returning %08x\n", ret);
6124 return ret;
6126 case WINED3DFMT_X1R5G5B5:
6127 case WINED3DFMT_A1R5G5B5:
6128 a = (a * 2) / 256;
6129 r = (r * 32) / 256;
6130 g = (g * 32) / 256;
6131 b = (b * 32) / 256;
6132 ret = a << 15;
6133 ret |= r << 10;
6134 ret |= g << 5;
6135 ret |= b << 0;
6136 TRACE("Returning %08x\n", ret);
6137 return ret;
6139 case WINED3DFMT_A8_UNORM:
6140 TRACE("Returning %08x\n", a);
6141 return a;
6143 case WINED3DFMT_X4R4G4B4:
6144 case WINED3DFMT_A4R4G4B4:
6145 a = (a * 16) / 256;
6146 r = (r * 16) / 256;
6147 g = (g * 16) / 256;
6148 b = (b * 16) / 256;
6149 ret = a << 12;
6150 ret |= r << 8;
6151 ret |= g << 4;
6152 ret |= b << 0;
6153 TRACE("Returning %08x\n", ret);
6154 return ret;
6156 case WINED3DFMT_R3G3B2:
6157 r = (r * 8) / 256;
6158 g = (g * 8) / 256;
6159 b = (b * 4) / 256;
6160 ret = r << 5;
6161 ret |= g << 2;
6162 ret |= b << 0;
6163 TRACE("Returning %08x\n", ret);
6164 return ret;
6166 case WINED3DFMT_X8B8G8R8:
6167 case WINED3DFMT_R8G8B8A8_UNORM:
6168 ret = a << 24;
6169 ret |= b << 16;
6170 ret |= g << 8;
6171 ret |= r << 0;
6172 TRACE("Returning %08x\n", ret);
6173 return ret;
6175 case WINED3DFMT_A2R10G10B10:
6176 a = (a * 4) / 256;
6177 r = (r * 1024) / 256;
6178 g = (g * 1024) / 256;
6179 b = (b * 1024) / 256;
6180 ret = a << 30;
6181 ret |= r << 20;
6182 ret |= g << 10;
6183 ret |= b << 0;
6184 TRACE("Returning %08x\n", ret);
6185 return ret;
6187 case WINED3DFMT_R10G10B10A2_UNORM:
6188 a = (a * 4) / 256;
6189 r = (r * 1024) / 256;
6190 g = (g * 1024) / 256;
6191 b = (b * 1024) / 256;
6192 ret = a << 30;
6193 ret |= b << 20;
6194 ret |= g << 10;
6195 ret |= r << 0;
6196 TRACE("Returning %08x\n", ret);
6197 return ret;
6199 default:
6200 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6201 return 0;
6205 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6207 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6208 WINEDDBLTFX BltFx;
6209 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6211 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6212 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6213 return WINED3DERR_INVALIDCALL;
6216 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6217 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
6218 color_fill_fbo(iface, pSurface, pRect, c);
6219 return WINED3D_OK;
6220 } else {
6221 /* Just forward this to the DirectDraw blitting engine */
6222 memset(&BltFx, 0, sizeof(BltFx));
6223 BltFx.dwSize = sizeof(BltFx);
6224 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
6225 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6226 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6230 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
6231 IWineD3DRendertargetView *rendertarget_view, const float color[4])
6233 IWineD3DResource *resource;
6234 IWineD3DSurface *surface;
6235 HRESULT hr;
6237 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
6238 if (FAILED(hr))
6240 ERR("Failed to get resource, hr %#x\n", hr);
6241 return;
6244 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
6246 FIXME("Only supported on surface resources\n");
6247 IWineD3DResource_Release(resource);
6248 return;
6251 surface = (IWineD3DSurface *)resource;
6253 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6255 color_fill_fbo(iface, surface, NULL, color);
6257 else
6259 WINEDDBLTFX BltFx;
6260 WINED3DCOLOR c;
6262 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
6264 c = ((DWORD)(color[2] * 255.0f));
6265 c |= ((DWORD)(color[1] * 255.0f)) << 8;
6266 c |= ((DWORD)(color[0] * 255.0f)) << 16;
6267 c |= ((DWORD)(color[3] * 255.0f)) << 24;
6269 /* Just forward this to the DirectDraw blitting engine */
6270 memset(&BltFx, 0, sizeof(BltFx));
6271 BltFx.dwSize = sizeof(BltFx);
6272 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
6273 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6274 if (FAILED(hr))
6276 ERR("Blt failed, hr %#x\n", hr);
6280 IWineD3DResource_Release(resource);
6283 /* rendertarget and depth stencil functions */
6284 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6285 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6287 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6288 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6289 return WINED3DERR_INVALIDCALL;
6292 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6293 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6294 /* Note inc ref on returned surface */
6295 if(*ppRenderTarget != NULL)
6296 IWineD3DSurface_AddRef(*ppRenderTarget);
6297 return WINED3D_OK;
6300 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6301 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6302 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6303 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6304 IWineD3DSwapChainImpl *Swapchain;
6305 HRESULT hr;
6307 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6309 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6310 if(hr != WINED3D_OK) {
6311 ERR("Can't get the swapchain\n");
6312 return hr;
6315 /* Make sure to release the swapchain */
6316 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6318 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6319 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6320 return WINED3DERR_INVALIDCALL;
6322 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6323 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6324 return WINED3DERR_INVALIDCALL;
6327 if(Swapchain->frontBuffer != Front) {
6328 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6330 if(Swapchain->frontBuffer)
6332 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6333 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
6335 Swapchain->frontBuffer = Front;
6337 if(Swapchain->frontBuffer) {
6338 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6339 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
6343 if(Back && !Swapchain->backBuffer) {
6344 /* We need memory for the back buffer array - only one back buffer this way */
6345 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6346 if(!Swapchain->backBuffer) {
6347 ERR("Out of memory\n");
6348 return E_OUTOFMEMORY;
6352 if(Swapchain->backBuffer[0] != Back) {
6353 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6355 /* What to do about the context here in the case of multithreading? Not sure.
6356 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6358 WARN("No active context?\n");
6360 ENTER_GL();
6361 if(!Swapchain->backBuffer[0]) {
6362 /* GL was told to draw to the front buffer at creation,
6363 * undo that
6365 glDrawBuffer(GL_BACK);
6366 checkGLcall("glDrawBuffer(GL_BACK)");
6367 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6368 Swapchain->presentParms.BackBufferCount = 1;
6369 } else if (!Back) {
6370 /* That makes problems - disable for now */
6371 /* glDrawBuffer(GL_FRONT); */
6372 checkGLcall("glDrawBuffer(GL_FRONT)");
6373 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6374 Swapchain->presentParms.BackBufferCount = 0;
6376 LEAVE_GL();
6378 if(Swapchain->backBuffer[0])
6380 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6381 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
6383 Swapchain->backBuffer[0] = Back;
6385 if(Swapchain->backBuffer[0]) {
6386 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6387 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
6388 } else {
6389 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6390 Swapchain->backBuffer = NULL;
6395 return WINED3D_OK;
6398 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6400 *ppZStencilSurface = This->stencilBufferTarget;
6401 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6403 if(*ppZStencilSurface != NULL) {
6404 /* Note inc ref on returned surface */
6405 IWineD3DSurface_AddRef(*ppZStencilSurface);
6406 return WINED3D_OK;
6407 } else {
6408 return WINED3DERR_NOTFOUND;
6412 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6413 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6415 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6416 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6417 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6418 GLenum gl_filter;
6419 POINT offset = {0, 0};
6421 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6422 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6423 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6424 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6426 switch (filter) {
6427 case WINED3DTEXF_LINEAR:
6428 gl_filter = GL_LINEAR;
6429 break;
6431 default:
6432 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6433 case WINED3DTEXF_NONE:
6434 case WINED3DTEXF_POINT:
6435 gl_filter = GL_NEAREST;
6436 break;
6439 /* Attach src surface to src fbo */
6440 src_swapchain = get_swapchain(src_surface);
6441 dst_swapchain = get_swapchain(dst_surface);
6443 if (src_swapchain) ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6444 else if (dst_swapchain) ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6445 else ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6447 if (src_swapchain) {
6448 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6450 TRACE("Source surface %p is onscreen\n", src_surface);
6451 /* Make sure the drawable is up to date. In the offscreen case
6452 * attach_surface_fbo() implicitly takes care of this. */
6453 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6455 if(buffer == GL_FRONT) {
6456 RECT windowsize;
6457 UINT h;
6458 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6459 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6460 h = windowsize.bottom - windowsize.top;
6461 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6462 src_rect->y1 = offset.y + h - src_rect->y1;
6463 src_rect->y2 = offset.y + h - src_rect->y2;
6464 } else {
6465 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6466 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6469 ENTER_GL();
6470 context_bind_fbo(This->activeContext, GL_READ_FRAMEBUFFER_EXT, NULL);
6471 glReadBuffer(buffer);
6472 checkGLcall("glReadBuffer()");
6473 } else {
6474 TRACE("Source surface %p is offscreen\n", src_surface);
6475 ENTER_GL();
6476 context_bind_fbo(This->activeContext, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6477 context_attach_surface_fbo(This->activeContext, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6478 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6479 checkGLcall("glReadBuffer()");
6480 context_attach_depth_stencil_fbo(This->activeContext, GL_READ_FRAMEBUFFER_EXT, NULL, FALSE);
6482 LEAVE_GL();
6484 /* Attach dst surface to dst fbo */
6485 if (dst_swapchain) {
6486 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6488 TRACE("Destination surface %p is onscreen\n", dst_surface);
6489 /* Make sure the drawable is up to date. In the offscreen case
6490 * attach_surface_fbo() implicitly takes care of this. */
6491 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6493 if(buffer == GL_FRONT) {
6494 RECT windowsize;
6495 UINT h;
6496 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6497 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6498 h = windowsize.bottom - windowsize.top;
6499 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6500 dst_rect->y1 = offset.y + h - dst_rect->y1;
6501 dst_rect->y2 = offset.y + h - dst_rect->y2;
6502 } else {
6503 /* Screen coords = window coords, surface height = window height */
6504 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6505 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6508 ENTER_GL();
6509 context_bind_fbo(This->activeContext, GL_DRAW_FRAMEBUFFER_EXT, NULL);
6510 glDrawBuffer(buffer);
6511 checkGLcall("glDrawBuffer()");
6512 } else {
6513 TRACE("Destination surface %p is offscreen\n", dst_surface);
6515 ENTER_GL();
6516 context_bind_fbo(This->activeContext, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6517 context_attach_surface_fbo(This->activeContext, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6518 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6519 checkGLcall("glDrawBuffer()");
6520 context_attach_depth_stencil_fbo(This->activeContext, GL_DRAW_FRAMEBUFFER_EXT, NULL, FALSE);
6522 glDisable(GL_SCISSOR_TEST);
6523 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6525 if (flip) {
6526 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6527 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6528 checkGLcall("glBlitFramebuffer()");
6529 } else {
6530 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6531 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6532 checkGLcall("glBlitFramebuffer()");
6535 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6537 if (This->activeContext->current_fbo) {
6538 context_bind_fbo(This->activeContext, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6539 } else {
6540 context_bind_fbo(This->activeContext, GL_FRAMEBUFFER_EXT, NULL);
6543 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6544 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6545 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6546 glDrawBuffer(GL_BACK);
6547 checkGLcall("glDrawBuffer()");
6549 LEAVE_GL();
6552 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6553 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6554 WINED3DVIEWPORT viewport;
6556 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6558 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6559 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6560 This, RenderTargetIndex, GL_LIMITS(buffers));
6561 return WINED3DERR_INVALIDCALL;
6564 /* MSDN says that null disables the render target
6565 but a device must always be associated with a render target
6566 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6568 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6569 FIXME("Trying to set render target 0 to NULL\n");
6570 return WINED3DERR_INVALIDCALL;
6572 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6573 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);
6574 return WINED3DERR_INVALIDCALL;
6577 /* If we are trying to set what we already have, don't bother */
6578 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6579 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6580 return WINED3D_OK;
6582 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6583 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6584 This->render_targets[RenderTargetIndex] = pRenderTarget;
6586 /* Render target 0 is special */
6587 if(RenderTargetIndex == 0) {
6588 /* Finally, reset the viewport as the MSDN states. */
6589 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6590 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6591 viewport.X = 0;
6592 viewport.Y = 0;
6593 viewport.MaxZ = 1.0f;
6594 viewport.MinZ = 0.0f;
6595 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6596 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6597 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6599 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6601 return WINED3D_OK;
6604 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6605 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6606 HRESULT hr = WINED3D_OK;
6607 IWineD3DSurface *tmp;
6609 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6611 if (pNewZStencil == This->stencilBufferTarget) {
6612 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6613 } else {
6614 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6615 * depending on the renter target implementation being used.
6616 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6617 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6618 * stencil buffer and incur an extra memory overhead
6619 ******************************************************/
6621 if (This->stencilBufferTarget) {
6622 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6623 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6624 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6625 } else {
6626 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6627 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6628 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6632 tmp = This->stencilBufferTarget;
6633 This->stencilBufferTarget = pNewZStencil;
6634 /* should we be calling the parent or the wined3d surface? */
6635 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6636 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6637 hr = WINED3D_OK;
6639 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6640 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6641 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6642 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6643 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6647 return hr;
6650 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6651 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6652 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6653 /* TODO: the use of Impl is deprecated. */
6654 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6655 WINED3DLOCKED_RECT lockedRect;
6657 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6659 /* some basic validation checks */
6660 if(This->cursorTexture) {
6661 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6662 ENTER_GL();
6663 glDeleteTextures(1, &This->cursorTexture);
6664 LEAVE_GL();
6665 This->cursorTexture = 0;
6668 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6669 This->haveHardwareCursor = TRUE;
6670 else
6671 This->haveHardwareCursor = FALSE;
6673 if(pCursorBitmap) {
6674 WINED3DLOCKED_RECT rect;
6676 /* MSDN: Cursor must be A8R8G8B8 */
6677 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format_desc->format)
6679 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6680 return WINED3DERR_INVALIDCALL;
6683 /* MSDN: Cursor must be smaller than the display mode */
6684 if(pSur->currentDesc.Width > This->ddraw_width ||
6685 pSur->currentDesc.Height > This->ddraw_height) {
6686 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);
6687 return WINED3DERR_INVALIDCALL;
6690 if (!This->haveHardwareCursor) {
6691 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6693 /* Do not store the surface's pointer because the application may
6694 * release it after setting the cursor image. Windows doesn't
6695 * addref the set surface, so we can't do this either without
6696 * creating circular refcount dependencies. Copy out the gl texture
6697 * instead.
6699 This->cursorWidth = pSur->currentDesc.Width;
6700 This->cursorHeight = pSur->currentDesc.Height;
6701 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6703 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION);
6704 char *mem, *bits = rect.pBits;
6705 GLint intfmt = glDesc->glInternal;
6706 GLint format = glDesc->glFormat;
6707 GLint type = glDesc->glType;
6708 INT height = This->cursorHeight;
6709 INT width = This->cursorWidth;
6710 INT bpp = glDesc->byte_count;
6711 INT i, sampler;
6713 /* Reformat the texture memory (pitch and width can be
6714 * different) */
6715 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6716 for(i = 0; i < height; i++)
6717 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6718 IWineD3DSurface_UnlockRect(pCursorBitmap);
6720 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6722 ENTER_GL();
6724 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6725 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6726 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6729 /* Make sure that a proper texture unit is selected */
6730 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6731 checkGLcall("glActiveTextureARB");
6732 sampler = This->rev_tex_unit_map[0];
6733 if (sampler != -1) {
6734 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6736 /* Create a new cursor texture */
6737 glGenTextures(1, &This->cursorTexture);
6738 checkGLcall("glGenTextures");
6739 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6740 checkGLcall("glBindTexture");
6741 /* Copy the bitmap memory into the cursor texture */
6742 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6743 HeapFree(GetProcessHeap(), 0, mem);
6744 checkGLcall("glTexImage2D");
6746 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6747 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6748 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6751 LEAVE_GL();
6753 else
6755 FIXME("A cursor texture was not returned.\n");
6756 This->cursorTexture = 0;
6759 else
6761 /* Draw a hardware cursor */
6762 ICONINFO cursorInfo;
6763 HCURSOR cursor;
6764 /* Create and clear maskBits because it is not needed for
6765 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6766 * chunks. */
6767 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6768 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6769 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6770 WINED3DLOCK_NO_DIRTY_UPDATE |
6771 WINED3DLOCK_READONLY
6773 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6774 pSur->currentDesc.Height);
6776 cursorInfo.fIcon = FALSE;
6777 cursorInfo.xHotspot = XHotSpot;
6778 cursorInfo.yHotspot = YHotSpot;
6779 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6780 pSur->currentDesc.Height, 1,
6781 1, &maskBits);
6782 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6783 pSur->currentDesc.Height, 1,
6784 32, lockedRect.pBits);
6785 IWineD3DSurface_UnlockRect(pCursorBitmap);
6786 /* Create our cursor and clean up. */
6787 cursor = CreateIconIndirect(&cursorInfo);
6788 SetCursor(cursor);
6789 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6790 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6791 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6792 This->hardwareCursor = cursor;
6793 HeapFree(GetProcessHeap(), 0, maskBits);
6797 This->xHotSpot = XHotSpot;
6798 This->yHotSpot = YHotSpot;
6799 return WINED3D_OK;
6802 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6803 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6804 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6806 This->xScreenSpace = XScreenSpace;
6807 This->yScreenSpace = YScreenSpace;
6809 return;
6813 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6814 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6815 BOOL oldVisible = This->bCursorVisible;
6816 POINT pt;
6818 TRACE("(%p) : visible(%d)\n", This, bShow);
6821 * When ShowCursor is first called it should make the cursor appear at the OS's last
6822 * known cursor position. Because of this, some applications just repetitively call
6823 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6825 GetCursorPos(&pt);
6826 This->xScreenSpace = pt.x;
6827 This->yScreenSpace = pt.y;
6829 if (This->haveHardwareCursor) {
6830 This->bCursorVisible = bShow;
6831 if (bShow)
6832 SetCursor(This->hardwareCursor);
6833 else
6834 SetCursor(NULL);
6836 else
6838 if (This->cursorTexture)
6839 This->bCursorVisible = bShow;
6842 return oldVisible;
6845 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6846 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6847 IWineD3DResourceImpl *resource;
6848 TRACE("(%p) : state (%u)\n", This, This->state);
6850 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6851 switch (This->state) {
6852 case WINED3D_OK:
6853 return WINED3D_OK;
6854 case WINED3DERR_DEVICELOST:
6856 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6857 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6858 return WINED3DERR_DEVICENOTRESET;
6860 return WINED3DERR_DEVICELOST;
6862 case WINED3DERR_DRIVERINTERNALERROR:
6863 return WINED3DERR_DRIVERINTERNALERROR;
6866 /* Unknown state */
6867 return WINED3DERR_DRIVERINTERNALERROR;
6870 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6871 TRACE("checking resource %p for eviction\n", resource);
6872 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6873 TRACE("Evicting %p\n", resource);
6874 IWineD3DResource_UnLoad(resource);
6876 IWineD3DResource_Release(resource);
6877 return S_OK;
6880 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6882 TRACE("(%p)\n", This);
6884 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6885 return WINED3D_OK;
6888 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6890 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6892 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6893 if(surface->Flags & SFLAG_DIBSECTION) {
6894 /* Release the DC */
6895 SelectObject(surface->hDC, surface->dib.holdbitmap);
6896 DeleteDC(surface->hDC);
6897 /* Release the DIB section */
6898 DeleteObject(surface->dib.DIBsection);
6899 surface->dib.bitmap_data = NULL;
6900 surface->resource.allocatedMemory = NULL;
6901 surface->Flags &= ~SFLAG_DIBSECTION;
6903 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6904 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6905 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
6906 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
6907 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6908 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6909 } else {
6910 surface->pow2Width = surface->pow2Height = 1;
6911 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6912 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6914 surface->glRect.left = 0;
6915 surface->glRect.top = 0;
6916 surface->glRect.right = surface->pow2Width;
6917 surface->glRect.bottom = surface->pow2Height;
6919 if (surface->texture_name)
6921 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6922 ENTER_GL();
6923 glDeleteTextures(1, &surface->texture_name);
6924 LEAVE_GL();
6925 surface->texture_name = 0;
6926 surface->Flags &= ~SFLAG_CLIENT;
6928 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6929 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6930 surface->Flags |= SFLAG_NONPOW2;
6931 } else {
6932 surface->Flags &= ~SFLAG_NONPOW2;
6934 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6935 surface->resource.allocatedMemory = NULL;
6936 surface->resource.heapMemory = NULL;
6937 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6938 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
6939 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
6940 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
6941 } else {
6942 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
6946 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6947 TRACE("Unloading resource %p\n", resource);
6948 IWineD3DResource_UnLoad(resource);
6949 IWineD3DResource_Release(resource);
6950 return S_OK;
6953 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6955 UINT i, count;
6956 WINED3DDISPLAYMODE m;
6957 HRESULT hr;
6959 /* All Windowed modes are supported, as is leaving the current mode */
6960 if(pp->Windowed) return TRUE;
6961 if(!pp->BackBufferWidth) return TRUE;
6962 if(!pp->BackBufferHeight) return TRUE;
6964 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
6965 for(i = 0; i < count; i++) {
6966 memset(&m, 0, sizeof(m));
6967 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
6968 if(FAILED(hr)) {
6969 ERR("EnumAdapterModes failed\n");
6971 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6972 /* Mode found, it is supported */
6973 return TRUE;
6976 /* Mode not found -> not supported */
6977 return FALSE;
6980 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6981 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6982 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6983 UINT i;
6984 IWineD3DBaseShaderImpl *shader;
6986 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6988 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6989 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6990 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6993 ENTER_GL();
6994 if(This->depth_blt_texture) {
6995 glDeleteTextures(1, &This->depth_blt_texture);
6996 This->depth_blt_texture = 0;
6998 if (This->depth_blt_rb) {
6999 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7000 This->depth_blt_rb = 0;
7001 This->depth_blt_rb_w = 0;
7002 This->depth_blt_rb_h = 0;
7004 LEAVE_GL();
7006 This->blitter->free_private(iface);
7007 This->frag_pipe->free_private(iface);
7008 This->shader_backend->shader_free_private(iface);
7010 ENTER_GL();
7011 for (i = 0; i < GL_LIMITS(textures); i++) {
7012 /* Textures are recreated below */
7013 glDeleteTextures(1, &This->dummyTextureName[i]);
7014 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7015 This->dummyTextureName[i] = 0;
7017 LEAVE_GL();
7019 while(This->numContexts) {
7020 DestroyContext(This, This->contexts[0]);
7022 This->activeContext = NULL;
7023 HeapFree(GetProcessHeap(), 0, swapchain->context);
7024 swapchain->context = NULL;
7025 swapchain->num_contexts = 0;
7028 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7029 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7030 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7031 HRESULT hr;
7032 IWineD3DSurfaceImpl *target;
7034 /* Recreate the primary swapchain's context */
7035 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7036 if(swapchain->backBuffer) {
7037 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7038 } else {
7039 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7041 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7042 &swapchain->presentParms);
7043 swapchain->num_contexts = 1;
7044 This->activeContext = swapchain->context[0];
7046 create_dummy_textures(This);
7048 hr = This->shader_backend->shader_alloc_private(iface);
7049 if(FAILED(hr)) {
7050 ERR("Failed to recreate shader private data\n");
7051 goto err_out;
7053 hr = This->frag_pipe->alloc_private(iface);
7054 if(FAILED(hr)) {
7055 TRACE("Fragment pipeline private data couldn't be allocated\n");
7056 goto err_out;
7058 hr = This->blitter->alloc_private(iface);
7059 if(FAILED(hr)) {
7060 TRACE("Blitter private data couldn't be allocated\n");
7061 goto err_out;
7064 return WINED3D_OK;
7066 err_out:
7067 This->blitter->free_private(iface);
7068 This->frag_pipe->free_private(iface);
7069 This->shader_backend->shader_free_private(iface);
7070 return hr;
7073 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7074 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7075 IWineD3DSwapChainImpl *swapchain;
7076 HRESULT hr;
7077 BOOL DisplayModeChanged = FALSE;
7078 WINED3DDISPLAYMODE mode;
7079 TRACE("(%p)\n", This);
7081 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7082 if(FAILED(hr)) {
7083 ERR("Failed to get the first implicit swapchain\n");
7084 return hr;
7087 if(!is_display_mode_supported(This, pPresentationParameters)) {
7088 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7089 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7090 pPresentationParameters->BackBufferHeight);
7091 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
7092 return WINED3DERR_INVALIDCALL;
7095 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7096 * on an existing gl context, so there's no real need for recreation.
7098 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7100 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7102 TRACE("New params:\n");
7103 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7104 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7105 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7106 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7107 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7108 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7109 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7110 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7111 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7112 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7113 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7114 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7115 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7117 /* No special treatment of these parameters. Just store them */
7118 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7119 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7120 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7121 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7123 /* What to do about these? */
7124 if(pPresentationParameters->BackBufferCount != 0 &&
7125 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7126 ERR("Cannot change the back buffer count yet\n");
7128 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7129 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7130 ERR("Cannot change the back buffer format yet\n");
7132 if(pPresentationParameters->hDeviceWindow != NULL &&
7133 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7134 ERR("Cannot change the device window yet\n");
7136 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7137 HRESULT hrc;
7139 TRACE("Creating the depth stencil buffer\n");
7141 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
7142 This->parent,
7143 pPresentationParameters->BackBufferWidth,
7144 pPresentationParameters->BackBufferHeight,
7145 pPresentationParameters->AutoDepthStencilFormat,
7146 pPresentationParameters->MultiSampleType,
7147 pPresentationParameters->MultiSampleQuality,
7148 FALSE,
7149 &This->auto_depth_stencil_buffer);
7151 if (FAILED(hrc)) {
7152 ERR("Failed to create the depth stencil buffer\n");
7153 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7154 return WINED3DERR_INVALIDCALL;
7158 /* Reset the depth stencil */
7159 if (pPresentationParameters->EnableAutoDepthStencil)
7160 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7161 else
7162 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7164 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7166 if(pPresentationParameters->Windowed) {
7167 mode.Width = swapchain->orig_width;
7168 mode.Height = swapchain->orig_height;
7169 mode.RefreshRate = 0;
7170 mode.Format = swapchain->presentParms.BackBufferFormat;
7171 } else {
7172 mode.Width = pPresentationParameters->BackBufferWidth;
7173 mode.Height = pPresentationParameters->BackBufferHeight;
7174 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7175 mode.Format = swapchain->presentParms.BackBufferFormat;
7178 /* Should Width == 800 && Height == 0 set 800x600? */
7179 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7180 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7181 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7183 UINT i;
7185 if(!pPresentationParameters->Windowed) {
7186 DisplayModeChanged = TRUE;
7188 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7189 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7191 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7192 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7193 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7195 if(This->auto_depth_stencil_buffer) {
7196 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7200 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7201 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7202 DisplayModeChanged) {
7204 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7206 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7207 if(swapchain->presentParms.Windowed) {
7208 /* switch from windowed to fs */
7209 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7210 pPresentationParameters->BackBufferWidth,
7211 pPresentationParameters->BackBufferHeight);
7212 } else {
7213 /* Fullscreen -> fullscreen mode change */
7214 MoveWindow(swapchain->win_handle, 0, 0,
7215 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7216 TRUE);
7218 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7219 /* Fullscreen -> windowed switch */
7220 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7222 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7223 } else if(!pPresentationParameters->Windowed) {
7224 DWORD style = This->style, exStyle = This->exStyle;
7225 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7226 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7227 * Reset to clear up their mess. Guild Wars also loses the device during that.
7229 This->style = 0;
7230 This->exStyle = 0;
7231 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7232 pPresentationParameters->BackBufferWidth,
7233 pPresentationParameters->BackBufferHeight);
7234 This->style = style;
7235 This->exStyle = exStyle;
7238 TRACE("Resetting stateblock\n");
7239 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
7240 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
7242 /* Note: No parent needed for initial internal stateblock */
7243 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
7244 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7245 else TRACE("Created stateblock %p\n", This->stateBlock);
7246 This->updateStateBlock = This->stateBlock;
7247 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
7249 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7250 if(FAILED(hr)) {
7251 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7254 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7255 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7257 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7258 * first use
7260 return hr;
7263 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7264 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7265 /** FIXME: always true at the moment **/
7266 if(!bEnableDialogs) {
7267 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7269 return WINED3D_OK;
7273 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7274 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7275 TRACE("(%p) : pParameters %p\n", This, pParameters);
7277 *pParameters = This->createParms;
7278 return WINED3D_OK;
7281 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7282 IWineD3DSwapChain *swapchain;
7284 TRACE("Relaying to swapchain\n");
7286 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7287 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7288 IWineD3DSwapChain_Release(swapchain);
7290 return;
7293 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7294 IWineD3DSwapChain *swapchain;
7296 TRACE("Relaying to swapchain\n");
7298 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7299 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7300 IWineD3DSwapChain_Release(swapchain);
7302 return;
7306 /** ********************************************************
7307 * Notification functions
7308 ** ********************************************************/
7309 /** This function must be called in the release of a resource when ref == 0,
7310 * the contents of resource must still be correct,
7311 * any handles to other resource held by the caller must be closed
7312 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7313 *****************************************************/
7314 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7316 TRACE("(%p) : Adding resource %p\n", This, resource);
7318 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7321 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7323 TRACE("(%p) : Removing resource %p\n", This, resource);
7325 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7328 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7330 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7331 int counter;
7333 TRACE("(%p) : resource %p\n", This, resource);
7335 context_resource_released((IWineD3DDevice *)This, resource, type);
7337 switch (type) {
7338 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7339 case WINED3DRTYPE_SURFACE: {
7340 unsigned int i;
7342 if (This->d3d_initialized)
7344 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7345 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7346 This->render_targets[i] = NULL;
7349 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7350 This->stencilBufferTarget = NULL;
7354 break;
7356 case WINED3DRTYPE_TEXTURE:
7357 case WINED3DRTYPE_CUBETEXTURE:
7358 case WINED3DRTYPE_VOLUMETEXTURE:
7359 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7360 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7361 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7362 This->stateBlock->textures[counter] = NULL;
7364 if (This->updateStateBlock != This->stateBlock ){
7365 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7366 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7367 This->updateStateBlock->textures[counter] = NULL;
7371 break;
7372 case WINED3DRTYPE_VOLUME:
7373 /* TODO: nothing really? */
7374 break;
7375 case WINED3DRTYPE_BUFFER:
7377 int streamNumber;
7378 TRACE("Cleaning up stream pointers\n");
7380 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7381 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7382 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7384 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7385 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7386 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7387 This->updateStateBlock->streamSource[streamNumber] = 0;
7388 /* Set changed flag? */
7391 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) */
7392 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7393 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7394 This->stateBlock->streamSource[streamNumber] = 0;
7399 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7400 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7401 This->updateStateBlock->pIndexData = NULL;
7404 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7405 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7406 This->stateBlock->pIndexData = NULL;
7410 break;
7412 default:
7413 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7414 break;
7418 /* Remove the resource from the resourceStore */
7419 device_resource_remove(This, resource);
7421 TRACE("Resource released\n");
7425 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7426 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7427 IWineD3DResourceImpl *resource, *cursor;
7428 HRESULT ret;
7429 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7431 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7432 TRACE("enumerating resource %p\n", resource);
7433 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7434 ret = pCallback((IWineD3DResource *) resource, pData);
7435 if(ret == S_FALSE) {
7436 TRACE("Canceling enumeration\n");
7437 break;
7440 return WINED3D_OK;
7443 /**********************************************************
7444 * IWineD3DDevice VTbl follows
7445 **********************************************************/
7447 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7449 /*** IUnknown methods ***/
7450 IWineD3DDeviceImpl_QueryInterface,
7451 IWineD3DDeviceImpl_AddRef,
7452 IWineD3DDeviceImpl_Release,
7453 /*** IWineD3DDevice methods ***/
7454 IWineD3DDeviceImpl_GetParent,
7455 /*** Creation methods**/
7456 IWineD3DDeviceImpl_CreateBuffer,
7457 IWineD3DDeviceImpl_CreateVertexBuffer,
7458 IWineD3DDeviceImpl_CreateIndexBuffer,
7459 IWineD3DDeviceImpl_CreateStateBlock,
7460 IWineD3DDeviceImpl_CreateSurface,
7461 IWineD3DDeviceImpl_CreateRendertargetView,
7462 IWineD3DDeviceImpl_CreateTexture,
7463 IWineD3DDeviceImpl_CreateVolumeTexture,
7464 IWineD3DDeviceImpl_CreateVolume,
7465 IWineD3DDeviceImpl_CreateCubeTexture,
7466 IWineD3DDeviceImpl_CreateQuery,
7467 IWineD3DDeviceImpl_CreateSwapChain,
7468 IWineD3DDeviceImpl_CreateVertexDeclaration,
7469 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7470 IWineD3DDeviceImpl_CreateVertexShader,
7471 IWineD3DDeviceImpl_CreatePixelShader,
7472 IWineD3DDeviceImpl_CreatePalette,
7473 /*** Odd functions **/
7474 IWineD3DDeviceImpl_Init3D,
7475 IWineD3DDeviceImpl_InitGDI,
7476 IWineD3DDeviceImpl_Uninit3D,
7477 IWineD3DDeviceImpl_UninitGDI,
7478 IWineD3DDeviceImpl_SetMultithreaded,
7479 IWineD3DDeviceImpl_EvictManagedResources,
7480 IWineD3DDeviceImpl_GetAvailableTextureMem,
7481 IWineD3DDeviceImpl_GetBackBuffer,
7482 IWineD3DDeviceImpl_GetCreationParameters,
7483 IWineD3DDeviceImpl_GetDeviceCaps,
7484 IWineD3DDeviceImpl_GetDirect3D,
7485 IWineD3DDeviceImpl_GetDisplayMode,
7486 IWineD3DDeviceImpl_SetDisplayMode,
7487 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7488 IWineD3DDeviceImpl_GetRasterStatus,
7489 IWineD3DDeviceImpl_GetSwapChain,
7490 IWineD3DDeviceImpl_Reset,
7491 IWineD3DDeviceImpl_SetDialogBoxMode,
7492 IWineD3DDeviceImpl_SetCursorProperties,
7493 IWineD3DDeviceImpl_SetCursorPosition,
7494 IWineD3DDeviceImpl_ShowCursor,
7495 IWineD3DDeviceImpl_TestCooperativeLevel,
7496 /*** Getters and setters **/
7497 IWineD3DDeviceImpl_SetClipPlane,
7498 IWineD3DDeviceImpl_GetClipPlane,
7499 IWineD3DDeviceImpl_SetClipStatus,
7500 IWineD3DDeviceImpl_GetClipStatus,
7501 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7502 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7503 IWineD3DDeviceImpl_SetDepthStencilSurface,
7504 IWineD3DDeviceImpl_GetDepthStencilSurface,
7505 IWineD3DDeviceImpl_SetGammaRamp,
7506 IWineD3DDeviceImpl_GetGammaRamp,
7507 IWineD3DDeviceImpl_SetIndices,
7508 IWineD3DDeviceImpl_GetIndices,
7509 IWineD3DDeviceImpl_SetBaseVertexIndex,
7510 IWineD3DDeviceImpl_GetBaseVertexIndex,
7511 IWineD3DDeviceImpl_SetLight,
7512 IWineD3DDeviceImpl_GetLight,
7513 IWineD3DDeviceImpl_SetLightEnable,
7514 IWineD3DDeviceImpl_GetLightEnable,
7515 IWineD3DDeviceImpl_SetMaterial,
7516 IWineD3DDeviceImpl_GetMaterial,
7517 IWineD3DDeviceImpl_SetNPatchMode,
7518 IWineD3DDeviceImpl_GetNPatchMode,
7519 IWineD3DDeviceImpl_SetPaletteEntries,
7520 IWineD3DDeviceImpl_GetPaletteEntries,
7521 IWineD3DDeviceImpl_SetPixelShader,
7522 IWineD3DDeviceImpl_GetPixelShader,
7523 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7524 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7525 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7526 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7527 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7528 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7529 IWineD3DDeviceImpl_SetRenderState,
7530 IWineD3DDeviceImpl_GetRenderState,
7531 IWineD3DDeviceImpl_SetRenderTarget,
7532 IWineD3DDeviceImpl_GetRenderTarget,
7533 IWineD3DDeviceImpl_SetFrontBackBuffers,
7534 IWineD3DDeviceImpl_SetSamplerState,
7535 IWineD3DDeviceImpl_GetSamplerState,
7536 IWineD3DDeviceImpl_SetScissorRect,
7537 IWineD3DDeviceImpl_GetScissorRect,
7538 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7539 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7540 IWineD3DDeviceImpl_SetStreamSource,
7541 IWineD3DDeviceImpl_GetStreamSource,
7542 IWineD3DDeviceImpl_SetStreamSourceFreq,
7543 IWineD3DDeviceImpl_GetStreamSourceFreq,
7544 IWineD3DDeviceImpl_SetTexture,
7545 IWineD3DDeviceImpl_GetTexture,
7546 IWineD3DDeviceImpl_SetTextureStageState,
7547 IWineD3DDeviceImpl_GetTextureStageState,
7548 IWineD3DDeviceImpl_SetTransform,
7549 IWineD3DDeviceImpl_GetTransform,
7550 IWineD3DDeviceImpl_SetVertexDeclaration,
7551 IWineD3DDeviceImpl_GetVertexDeclaration,
7552 IWineD3DDeviceImpl_SetVertexShader,
7553 IWineD3DDeviceImpl_GetVertexShader,
7554 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7555 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7556 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7557 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7558 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7559 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7560 IWineD3DDeviceImpl_SetViewport,
7561 IWineD3DDeviceImpl_GetViewport,
7562 IWineD3DDeviceImpl_MultiplyTransform,
7563 IWineD3DDeviceImpl_ValidateDevice,
7564 IWineD3DDeviceImpl_ProcessVertices,
7565 /*** State block ***/
7566 IWineD3DDeviceImpl_BeginStateBlock,
7567 IWineD3DDeviceImpl_EndStateBlock,
7568 /*** Scene management ***/
7569 IWineD3DDeviceImpl_BeginScene,
7570 IWineD3DDeviceImpl_EndScene,
7571 IWineD3DDeviceImpl_Present,
7572 IWineD3DDeviceImpl_Clear,
7573 IWineD3DDeviceImpl_ClearRendertargetView,
7574 /*** Drawing ***/
7575 IWineD3DDeviceImpl_SetPrimitiveType,
7576 IWineD3DDeviceImpl_GetPrimitiveType,
7577 IWineD3DDeviceImpl_DrawPrimitive,
7578 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7579 IWineD3DDeviceImpl_DrawPrimitiveUP,
7580 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7581 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7582 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7583 IWineD3DDeviceImpl_DrawRectPatch,
7584 IWineD3DDeviceImpl_DrawTriPatch,
7585 IWineD3DDeviceImpl_DeletePatch,
7586 IWineD3DDeviceImpl_ColorFill,
7587 IWineD3DDeviceImpl_UpdateTexture,
7588 IWineD3DDeviceImpl_UpdateSurface,
7589 IWineD3DDeviceImpl_GetFrontBufferData,
7590 /*** object tracking ***/
7591 IWineD3DDeviceImpl_EnumResources
7594 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7595 WINED3DRS_ALPHABLENDENABLE ,
7596 WINED3DRS_ALPHAFUNC ,
7597 WINED3DRS_ALPHAREF ,
7598 WINED3DRS_ALPHATESTENABLE ,
7599 WINED3DRS_BLENDOP ,
7600 WINED3DRS_COLORWRITEENABLE ,
7601 WINED3DRS_DESTBLEND ,
7602 WINED3DRS_DITHERENABLE ,
7603 WINED3DRS_FILLMODE ,
7604 WINED3DRS_FOGDENSITY ,
7605 WINED3DRS_FOGEND ,
7606 WINED3DRS_FOGSTART ,
7607 WINED3DRS_LASTPIXEL ,
7608 WINED3DRS_SHADEMODE ,
7609 WINED3DRS_SRCBLEND ,
7610 WINED3DRS_STENCILENABLE ,
7611 WINED3DRS_STENCILFAIL ,
7612 WINED3DRS_STENCILFUNC ,
7613 WINED3DRS_STENCILMASK ,
7614 WINED3DRS_STENCILPASS ,
7615 WINED3DRS_STENCILREF ,
7616 WINED3DRS_STENCILWRITEMASK ,
7617 WINED3DRS_STENCILZFAIL ,
7618 WINED3DRS_TEXTUREFACTOR ,
7619 WINED3DRS_WRAP0 ,
7620 WINED3DRS_WRAP1 ,
7621 WINED3DRS_WRAP2 ,
7622 WINED3DRS_WRAP3 ,
7623 WINED3DRS_WRAP4 ,
7624 WINED3DRS_WRAP5 ,
7625 WINED3DRS_WRAP6 ,
7626 WINED3DRS_WRAP7 ,
7627 WINED3DRS_ZENABLE ,
7628 WINED3DRS_ZFUNC ,
7629 WINED3DRS_ZWRITEENABLE
7632 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7633 WINED3DTSS_ALPHAARG0 ,
7634 WINED3DTSS_ALPHAARG1 ,
7635 WINED3DTSS_ALPHAARG2 ,
7636 WINED3DTSS_ALPHAOP ,
7637 WINED3DTSS_BUMPENVLOFFSET ,
7638 WINED3DTSS_BUMPENVLSCALE ,
7639 WINED3DTSS_BUMPENVMAT00 ,
7640 WINED3DTSS_BUMPENVMAT01 ,
7641 WINED3DTSS_BUMPENVMAT10 ,
7642 WINED3DTSS_BUMPENVMAT11 ,
7643 WINED3DTSS_COLORARG0 ,
7644 WINED3DTSS_COLORARG1 ,
7645 WINED3DTSS_COLORARG2 ,
7646 WINED3DTSS_COLOROP ,
7647 WINED3DTSS_RESULTARG ,
7648 WINED3DTSS_TEXCOORDINDEX ,
7649 WINED3DTSS_TEXTURETRANSFORMFLAGS
7652 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7653 WINED3DSAMP_ADDRESSU ,
7654 WINED3DSAMP_ADDRESSV ,
7655 WINED3DSAMP_ADDRESSW ,
7656 WINED3DSAMP_BORDERCOLOR ,
7657 WINED3DSAMP_MAGFILTER ,
7658 WINED3DSAMP_MINFILTER ,
7659 WINED3DSAMP_MIPFILTER ,
7660 WINED3DSAMP_MIPMAPLODBIAS ,
7661 WINED3DSAMP_MAXMIPLEVEL ,
7662 WINED3DSAMP_MAXANISOTROPY ,
7663 WINED3DSAMP_SRGBTEXTURE ,
7664 WINED3DSAMP_ELEMENTINDEX
7667 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7668 WINED3DRS_AMBIENT ,
7669 WINED3DRS_AMBIENTMATERIALSOURCE ,
7670 WINED3DRS_CLIPPING ,
7671 WINED3DRS_CLIPPLANEENABLE ,
7672 WINED3DRS_COLORVERTEX ,
7673 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7674 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7675 WINED3DRS_FOGDENSITY ,
7676 WINED3DRS_FOGEND ,
7677 WINED3DRS_FOGSTART ,
7678 WINED3DRS_FOGTABLEMODE ,
7679 WINED3DRS_FOGVERTEXMODE ,
7680 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7681 WINED3DRS_LIGHTING ,
7682 WINED3DRS_LOCALVIEWER ,
7683 WINED3DRS_MULTISAMPLEANTIALIAS ,
7684 WINED3DRS_MULTISAMPLEMASK ,
7685 WINED3DRS_NORMALIZENORMALS ,
7686 WINED3DRS_PATCHEDGESTYLE ,
7687 WINED3DRS_POINTSCALE_A ,
7688 WINED3DRS_POINTSCALE_B ,
7689 WINED3DRS_POINTSCALE_C ,
7690 WINED3DRS_POINTSCALEENABLE ,
7691 WINED3DRS_POINTSIZE ,
7692 WINED3DRS_POINTSIZE_MAX ,
7693 WINED3DRS_POINTSIZE_MIN ,
7694 WINED3DRS_POINTSPRITEENABLE ,
7695 WINED3DRS_RANGEFOGENABLE ,
7696 WINED3DRS_SPECULARMATERIALSOURCE ,
7697 WINED3DRS_TWEENFACTOR ,
7698 WINED3DRS_VERTEXBLEND ,
7699 WINED3DRS_CULLMODE ,
7700 WINED3DRS_FOGCOLOR
7703 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7704 WINED3DTSS_TEXCOORDINDEX ,
7705 WINED3DTSS_TEXTURETRANSFORMFLAGS
7708 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7709 WINED3DSAMP_DMAPOFFSET
7712 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7713 DWORD rep = This->StateTable[state].representative;
7714 DWORD idx;
7715 BYTE shift;
7716 UINT i;
7717 WineD3DContext *context;
7719 if(!rep) return;
7720 for(i = 0; i < This->numContexts; i++) {
7721 context = This->contexts[i];
7722 if(isStateDirty(context, rep)) continue;
7724 context->dirtyArray[context->numDirtyEntries++] = rep;
7725 idx = rep >> 5;
7726 shift = rep & 0x1f;
7727 context->isStateDirty[idx] |= (1 << shift);
7731 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7732 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7733 /* The drawable size of a pbuffer render target is the current pbuffer size
7735 *width = dev->pbufferWidth;
7736 *height = dev->pbufferHeight;
7739 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7740 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7742 *width = This->pow2Width;
7743 *height = This->pow2Height;
7746 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7747 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7748 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7749 * current context's drawable, which is the size of the back buffer of the swapchain
7750 * the active context belongs to. The back buffer of the swapchain is stored as the
7751 * surface the context belongs to.
7753 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7754 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;