wined3d: Make it clear that glFlush and glFinish are WGL functions.
[wine/testsucceed.git] / dlls / wined3d / device.c
blob00a4c960a56c8c0aa0fb92809cfc0ad7e4829bc3
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(), 0, sizeof(struct wined3d_occlusion_query));
1195 ((struct wined3d_occlusion_query *)object->extendedData)->context = NULL;
1196 break;
1198 case WINED3DQUERYTYPE_EVENT:
1199 object->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_event_query));
1200 ((struct wined3d_event_query *)object->extendedData)->context = NULL;
1201 break;
1203 case WINED3DQUERYTYPE_VCACHE:
1204 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1205 case WINED3DQUERYTYPE_VERTEXSTATS:
1206 case WINED3DQUERYTYPE_TIMESTAMP:
1207 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1208 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1209 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1210 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1211 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1212 case WINED3DQUERYTYPE_PIXELTIMINGS:
1213 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1214 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1215 default:
1216 object->extendedData = 0;
1217 FIXME("(%p) Unhandled query type %d\n",This , Type);
1219 TRACE("(%p) : Created Query %p\n", This, object);
1220 return WINED3D_OK;
1223 /*****************************************************************************
1224 * IWineD3DDeviceImpl_SetupFullscreenWindow
1226 * Helper function that modifies a HWND's Style and ExStyle for proper
1227 * fullscreen use.
1229 * Params:
1230 * iface: Pointer to the IWineD3DDevice interface
1231 * window: Window to setup
1233 *****************************************************************************/
1234 static LONG fullscreen_style(LONG orig_style) {
1235 LONG style = orig_style;
1236 style &= ~WS_CAPTION;
1237 style &= ~WS_THICKFRAME;
1239 /* Make sure the window is managed, otherwise we won't get keyboard input */
1240 style |= WS_POPUP | WS_SYSMENU;
1242 return style;
1245 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1246 LONG exStyle = orig_exStyle;
1248 /* Filter out window decorations */
1249 exStyle &= ~WS_EX_WINDOWEDGE;
1250 exStyle &= ~WS_EX_CLIENTEDGE;
1252 return exStyle;
1255 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1256 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1258 LONG style, exStyle;
1259 /* Don't do anything if an original style is stored.
1260 * That shouldn't happen
1262 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1263 if (This->style || This->exStyle) {
1264 ERR("(%p): Want to change the window parameters of HWND %p, but "
1265 "another style is stored for restoration afterwards\n", This, window);
1268 /* Get the parameters and save them */
1269 style = GetWindowLongW(window, GWL_STYLE);
1270 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1271 This->style = style;
1272 This->exStyle = exStyle;
1274 style = fullscreen_style(style);
1275 exStyle = fullscreen_exStyle(exStyle);
1277 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1278 This->style, This->exStyle, style, exStyle);
1280 SetWindowLongW(window, GWL_STYLE, style);
1281 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1283 /* Inform the window about the update. */
1284 SetWindowPos(window, HWND_TOP, 0, 0,
1285 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1288 /*****************************************************************************
1289 * IWineD3DDeviceImpl_RestoreWindow
1291 * Helper function that restores a windows' properties when taking it out
1292 * of fullscreen mode
1294 * Params:
1295 * iface: Pointer to the IWineD3DDevice interface
1296 * window: Window to setup
1298 *****************************************************************************/
1299 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1300 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1301 LONG style, exStyle;
1303 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1304 * switch, do nothing
1306 if (!This->style && !This->exStyle) return;
1308 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1309 This, window, This->style, This->exStyle);
1311 style = GetWindowLongW(window, GWL_STYLE);
1312 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1314 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1315 * Some applications change it before calling Reset() when switching between windowed and
1316 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1318 if(style == fullscreen_style(This->style) &&
1319 exStyle == fullscreen_style(This->exStyle)) {
1320 SetWindowLongW(window, GWL_STYLE, This->style);
1321 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1324 /* Delete the old values */
1325 This->style = 0;
1326 This->exStyle = 0;
1328 /* Inform the window about the update */
1329 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1330 0, 0, 0, 0, /* Pos, Size, ignored */
1331 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1334 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1335 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1336 WINED3DPRESENT_PARAMETERS *pPresentationParameters, IWineD3DSwapChain **ppSwapChain,
1337 IUnknown *parent, WINED3DSURFTYPE surface_type)
1339 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1341 HDC hDc;
1342 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1343 HRESULT hr;
1344 IUnknown *bufferParent;
1345 BOOL displaymode_set = FALSE;
1346 WINED3DDISPLAYMODE Mode;
1347 const struct GlPixelFormatDesc *format_desc;
1349 TRACE("(%p) : Created Additional Swap Chain\n", This);
1351 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1352 * does a device hold a reference to a swap chain giving them a lifetime of the device
1353 * or does the swap chain notify the device of its destruction.
1354 *******************************/
1356 /* Check the params */
1357 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1358 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1359 return WINED3DERR_INVALIDCALL;
1360 } else if (pPresentationParameters->BackBufferCount > 1) {
1361 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");
1364 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1365 if(!object)
1367 ERR("Out of memory\n");
1368 *ppSwapChain = NULL;
1369 return WINED3DERR_OUTOFVIDEOMEMORY;
1372 switch(surface_type) {
1373 case SURFACE_GDI:
1374 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1375 break;
1376 case SURFACE_OPENGL:
1377 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1378 break;
1379 case SURFACE_UNKNOWN:
1380 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1381 HeapFree(GetProcessHeap(), 0, object);
1382 return WINED3DERR_INVALIDCALL;
1384 object->wineD3DDevice = This;
1385 object->parent = parent;
1386 object->ref = 1;
1388 *ppSwapChain = (IWineD3DSwapChain *)object;
1390 /*********************
1391 * Lookup the window Handle and the relating X window handle
1392 ********************/
1394 /* Setup hwnd we are using, plus which display this equates to */
1395 object->win_handle = pPresentationParameters->hDeviceWindow;
1396 if (!object->win_handle) {
1397 object->win_handle = This->createParms.hFocusWindow;
1399 if(!pPresentationParameters->Windowed && object->win_handle) {
1400 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1401 pPresentationParameters->BackBufferWidth,
1402 pPresentationParameters->BackBufferHeight);
1405 hDc = GetDC(object->win_handle);
1406 TRACE("Using hDc %p\n", hDc);
1408 if (NULL == hDc) {
1409 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1410 return WINED3DERR_NOTAVAILABLE;
1413 /* Get info on the current display setup */
1414 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1415 object->orig_width = Mode.Width;
1416 object->orig_height = Mode.Height;
1417 object->orig_fmt = Mode.Format;
1418 format_desc = getFormatDescEntry(Mode.Format, &GLINFO_LOCATION);
1420 if (pPresentationParameters->Windowed &&
1421 ((pPresentationParameters->BackBufferWidth == 0) ||
1422 (pPresentationParameters->BackBufferHeight == 0) ||
1423 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1425 RECT Rect;
1426 GetClientRect(object->win_handle, &Rect);
1428 if (pPresentationParameters->BackBufferWidth == 0) {
1429 pPresentationParameters->BackBufferWidth = Rect.right;
1430 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1432 if (pPresentationParameters->BackBufferHeight == 0) {
1433 pPresentationParameters->BackBufferHeight = Rect.bottom;
1434 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1436 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1437 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1438 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1442 /* Put the correct figures in the presentation parameters */
1443 TRACE("Copying across presentation parameters\n");
1444 object->presentParms = *pPresentationParameters;
1446 TRACE("calling rendertarget CB\n");
1447 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1448 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1449 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1450 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->frontBuffer);
1451 if (SUCCEEDED(hr)) {
1452 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1453 ((IWineD3DSurfaceImpl *)object->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
1454 if(surface_type == SURFACE_OPENGL) {
1455 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1457 } else {
1458 ERR("Failed to create the front buffer\n");
1459 goto error;
1462 /*********************
1463 * Windowed / Fullscreen
1464 *******************/
1467 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1468 * so we should really check to see if there is a fullscreen swapchain already
1469 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1470 **************************************/
1472 if (!pPresentationParameters->Windowed) {
1473 WINED3DDISPLAYMODE mode;
1476 /* Change the display settings */
1477 mode.Width = pPresentationParameters->BackBufferWidth;
1478 mode.Height = pPresentationParameters->BackBufferHeight;
1479 mode.Format = pPresentationParameters->BackBufferFormat;
1480 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1482 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1483 displaymode_set = TRUE;
1487 * Create an opengl context for the display visual
1488 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1489 * use different properties after that point in time. FIXME: How to handle when requested format
1490 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1491 * it chooses is identical to the one already being used!
1492 **********************************/
1493 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1495 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1496 if(!object->context) {
1497 ERR("Failed to create the context array\n");
1498 hr = E_OUTOFMEMORY;
1499 goto error;
1501 object->num_contexts = 1;
1503 if(surface_type == SURFACE_OPENGL) {
1504 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1505 if (!object->context[0]) {
1506 ERR("Failed to create a new context\n");
1507 hr = WINED3DERR_NOTAVAILABLE;
1508 goto error;
1509 } else {
1510 TRACE("Context created (HWND=%p, glContext=%p)\n",
1511 object->win_handle, object->context[0]->glCtx);
1515 /*********************
1516 * Create the back, front and stencil buffers
1517 *******************/
1518 if(object->presentParms.BackBufferCount > 0) {
1519 UINT i;
1521 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1522 if(!object->backBuffer) {
1523 ERR("Out of memory\n");
1524 hr = E_OUTOFMEMORY;
1525 goto error;
1528 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1529 TRACE("calling rendertarget CB\n");
1530 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1531 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1532 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1533 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->backBuffer[i]);
1534 if(SUCCEEDED(hr)) {
1535 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1536 ((IWineD3DSurfaceImpl *)object->backBuffer[i])->Flags |= SFLAG_SWAPCHAIN;
1537 } else {
1538 ERR("Cannot create new back buffer\n");
1539 goto error;
1541 if(surface_type == SURFACE_OPENGL) {
1542 ENTER_GL();
1543 glDrawBuffer(GL_BACK);
1544 checkGLcall("glDrawBuffer(GL_BACK)");
1545 LEAVE_GL();
1548 } else {
1549 object->backBuffer = NULL;
1551 /* Single buffering - draw to front buffer */
1552 if(surface_type == SURFACE_OPENGL) {
1553 ENTER_GL();
1554 glDrawBuffer(GL_FRONT);
1555 checkGLcall("glDrawBuffer(GL_FRONT)");
1556 LEAVE_GL();
1560 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1561 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1562 TRACE("Creating depth stencil buffer\n");
1563 if (This->auto_depth_stencil_buffer == NULL ) {
1564 hr = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent, parent,
1565 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1566 object->presentParms.AutoDepthStencilFormat, object->presentParms.MultiSampleType,
1567 object->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */,
1568 &This->auto_depth_stencil_buffer);
1569 if (SUCCEEDED(hr)) {
1570 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1571 } else {
1572 ERR("Failed to create the auto depth stencil\n");
1573 goto error;
1578 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1580 TRACE("Created swapchain %p\n", object);
1581 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1582 return WINED3D_OK;
1584 error:
1585 if (displaymode_set) {
1586 DEVMODEW devmode;
1587 RECT clip_rc;
1589 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1590 ClipCursor(NULL);
1592 /* Change the display settings */
1593 memset(&devmode, 0, sizeof(devmode));
1594 devmode.dmSize = sizeof(devmode);
1595 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1596 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1597 devmode.dmPelsWidth = object->orig_width;
1598 devmode.dmPelsHeight = object->orig_height;
1599 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1602 if (object->backBuffer) {
1603 UINT i;
1604 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1605 if(object->backBuffer[i]) {
1606 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1607 IUnknown_Release(bufferParent); /* once for the get parent */
1608 if (IUnknown_Release(bufferParent) > 0) {
1609 FIXME("(%p) Something's still holding the back buffer\n",This);
1613 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1614 object->backBuffer = NULL;
1616 if(object->context && object->context[0])
1617 DestroyContext(This, object->context[0]);
1618 if(object->frontBuffer) {
1619 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1620 IUnknown_Release(bufferParent); /* once for the get parent */
1621 if (IUnknown_Release(bufferParent) > 0) {
1622 FIXME("(%p) Something's still holding the front buffer\n",This);
1625 HeapFree(GetProcessHeap(), 0, object);
1626 return hr;
1629 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1630 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1632 TRACE("(%p)\n", This);
1634 return This->NumberOfSwapChains;
1637 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1638 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1639 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1641 if(iSwapChain < This->NumberOfSwapChains) {
1642 *pSwapChain = This->swapchains[iSwapChain];
1643 IWineD3DSwapChain_AddRef(*pSwapChain);
1644 TRACE("(%p) returning %p\n", This, *pSwapChain);
1645 return WINED3D_OK;
1646 } else {
1647 TRACE("Swapchain out of range\n");
1648 *pSwapChain = NULL;
1649 return WINED3DERR_INVALIDCALL;
1653 /*****
1654 * Vertex Declaration
1655 *****/
1656 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1657 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1658 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1659 IWineD3DVertexDeclarationImpl *object = NULL;
1660 HRESULT hr = WINED3D_OK;
1662 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1663 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1665 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1666 if(!object)
1668 ERR("Out of memory\n");
1669 *ppVertexDeclaration = NULL;
1670 return WINED3DERR_OUTOFVIDEOMEMORY;
1673 object->lpVtbl = &IWineD3DVertexDeclaration_Vtbl;
1674 object->wineD3DDevice = This;
1675 object->parent = parent;
1676 object->ref = 1;
1678 *ppVertexDeclaration = (IWineD3DVertexDeclaration *)object;
1680 hr = vertexdeclaration_init(object, elements, element_count);
1682 if(FAILED(hr)) {
1683 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
1684 *ppVertexDeclaration = NULL;
1687 return hr;
1690 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1691 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1693 unsigned int idx, idx2;
1694 unsigned int offset;
1695 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1696 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1697 BOOL has_blend_idx = has_blend &&
1698 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1699 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1700 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1701 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1702 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1703 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1704 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1706 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1707 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1708 WINED3DVERTEXELEMENT *elements = NULL;
1710 unsigned int size;
1711 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1712 if (has_blend_idx) num_blends--;
1714 /* Compute declaration size */
1715 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1716 has_psize + has_diffuse + has_specular + num_textures;
1718 /* convert the declaration */
1719 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1720 if (!elements) return ~0U;
1722 idx = 0;
1723 if (has_pos) {
1724 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1725 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1726 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
1728 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1729 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1730 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1732 else {
1733 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1734 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1736 elements[idx].usage_idx = 0;
1737 idx++;
1739 if (has_blend && (num_blends > 0)) {
1740 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1741 elements[idx].format = WINED3DFMT_A8R8G8B8;
1742 else {
1743 switch(num_blends) {
1744 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
1745 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
1746 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
1747 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
1748 default:
1749 ERR("Unexpected amount of blend values: %u\n", num_blends);
1752 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1753 elements[idx].usage_idx = 0;
1754 idx++;
1756 if (has_blend_idx) {
1757 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1758 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1759 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
1760 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1761 elements[idx].format = WINED3DFMT_A8R8G8B8;
1762 else
1763 elements[idx].format = WINED3DFMT_R32_FLOAT;
1764 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
1765 elements[idx].usage_idx = 0;
1766 idx++;
1768 if (has_normal) {
1769 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1770 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
1771 elements[idx].usage_idx = 0;
1772 idx++;
1774 if (has_psize) {
1775 elements[idx].format = WINED3DFMT_R32_FLOAT;
1776 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
1777 elements[idx].usage_idx = 0;
1778 idx++;
1780 if (has_diffuse) {
1781 elements[idx].format = WINED3DFMT_A8R8G8B8;
1782 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1783 elements[idx].usage_idx = 0;
1784 idx++;
1786 if (has_specular) {
1787 elements[idx].format = WINED3DFMT_A8R8G8B8;
1788 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1789 elements[idx].usage_idx = 1;
1790 idx++;
1792 for (idx2 = 0; idx2 < num_textures; idx2++) {
1793 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1794 switch (numcoords) {
1795 case WINED3DFVF_TEXTUREFORMAT1:
1796 elements[idx].format = WINED3DFMT_R32_FLOAT;
1797 break;
1798 case WINED3DFVF_TEXTUREFORMAT2:
1799 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
1800 break;
1801 case WINED3DFVF_TEXTUREFORMAT3:
1802 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1803 break;
1804 case WINED3DFVF_TEXTUREFORMAT4:
1805 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1806 break;
1808 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
1809 elements[idx].usage_idx = idx2;
1810 idx++;
1813 /* Now compute offsets, and initialize the rest of the fields */
1814 for (idx = 0, offset = 0; idx < size; ++idx)
1816 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
1817 elements[idx].input_slot = 0;
1818 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1819 elements[idx].offset = offset;
1820 offset += format_desc->component_count * format_desc->component_size;
1823 *ppVertexElements = elements;
1824 return size;
1827 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1828 WINED3DVERTEXELEMENT* elements = NULL;
1829 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1830 unsigned int size;
1831 DWORD hr;
1833 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1834 if (size == ~0U) return WINED3DERR_OUTOFVIDEOMEMORY;
1836 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1837 HeapFree(GetProcessHeap(), 0, elements);
1838 if (hr != S_OK) return hr;
1840 return WINED3D_OK;
1843 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1844 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1845 IWineD3DVertexShader **ppVertexShader, IUnknown *parent)
1847 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1848 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1849 HRESULT hr = WINED3D_OK;
1851 if (!pFunction) return WINED3DERR_INVALIDCALL;
1853 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1854 if (!object)
1856 ERR("Out of memory\n");
1857 *ppVertexShader = NULL;
1858 return WINED3DERR_OUTOFVIDEOMEMORY;
1861 object->lpVtbl = &IWineD3DVertexShader_Vtbl;
1862 object->parent = parent;
1863 shader_init(&object->baseShader, iface);
1864 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1865 *ppVertexShader = (IWineD3DVertexShader *)object;
1867 TRACE("(%p) : Created vertex shader %p\n", This, *ppVertexShader);
1869 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction, output_signature);
1870 if (FAILED(hr))
1872 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
1873 IWineD3DVertexShader_Release(*ppVertexShader);
1874 *ppVertexShader = NULL;
1875 return hr;
1878 return hr;
1881 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1882 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1883 IWineD3DPixelShader **ppPixelShader, IUnknown *parent)
1885 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1886 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1887 HRESULT hr = WINED3D_OK;
1889 if (!pFunction) return WINED3DERR_INVALIDCALL;
1891 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1892 if (!object)
1894 ERR("Out of memory\n");
1895 *ppPixelShader = NULL;
1896 return WINED3DERR_OUTOFVIDEOMEMORY;
1899 object->lpVtbl = &IWineD3DPixelShader_Vtbl;
1900 object->parent = parent;
1901 shader_init(&object->baseShader, iface);
1902 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1903 *ppPixelShader = (IWineD3DPixelShader *)object;
1905 TRACE("(%p) : Created pixel shader %p\n", This, *ppPixelShader);
1907 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction, output_signature);
1908 if (FAILED(hr))
1910 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
1911 IWineD3DPixelShader_Release(*ppPixelShader);
1912 *ppPixelShader = NULL;
1913 return hr;
1916 return hr;
1919 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1920 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1922 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1923 IWineD3DPaletteImpl *object;
1924 HRESULT hr;
1925 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1927 /* Create the new object */
1928 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1929 if(!object) {
1930 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1931 return E_OUTOFMEMORY;
1934 object->lpVtbl = &IWineD3DPalette_Vtbl;
1935 object->ref = 1;
1936 object->Flags = Flags;
1937 object->parent = Parent;
1938 object->wineD3DDevice = This;
1939 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1940 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1942 if(!object->hpal) {
1943 HeapFree( GetProcessHeap(), 0, object);
1944 return E_OUTOFMEMORY;
1947 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1948 if(FAILED(hr)) {
1949 IWineD3DPalette_Release((IWineD3DPalette *) object);
1950 return hr;
1953 *Palette = (IWineD3DPalette *) object;
1955 return WINED3D_OK;
1958 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1959 HBITMAP hbm;
1960 BITMAP bm;
1961 HRESULT hr;
1962 HDC dcb = NULL, dcs = NULL;
1963 WINEDDCOLORKEY colorkey;
1965 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1966 if(hbm)
1968 GetObjectA(hbm, sizeof(BITMAP), &bm);
1969 dcb = CreateCompatibleDC(NULL);
1970 if(!dcb) goto out;
1971 SelectObject(dcb, hbm);
1973 else
1975 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1976 * couldn't be loaded
1978 memset(&bm, 0, sizeof(bm));
1979 bm.bmWidth = 32;
1980 bm.bmHeight = 32;
1983 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5, TRUE,
1984 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL, NULL);
1985 if(FAILED(hr)) {
1986 ERR("Wine logo requested, but failed to create surface\n");
1987 goto out;
1990 if(dcb) {
1991 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1992 if(FAILED(hr)) goto out;
1993 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1994 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1996 colorkey.dwColorSpaceLowValue = 0;
1997 colorkey.dwColorSpaceHighValue = 0;
1998 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1999 } else {
2000 /* Fill the surface with a white color to show that wined3d is there */
2001 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2004 out:
2005 if(dcb) {
2006 DeleteDC(dcb);
2008 if(hbm) {
2009 DeleteObject(hbm);
2011 return;
2014 /* Context activation is done by the caller. */
2015 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2016 unsigned int i;
2017 /* Under DirectX you can have texture stage operations even if no texture is
2018 bound, whereas opengl will only do texture operations when a valid texture is
2019 bound. We emulate this by creating dummy textures and binding them to each
2020 texture stage, but disable all stages by default. Hence if a stage is enabled
2021 then the default texture will kick in until replaced by a SetTexture call */
2022 ENTER_GL();
2024 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2025 /* The dummy texture does not have client storage backing */
2026 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2027 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2029 for (i = 0; i < GL_LIMITS(textures); i++) {
2030 GLubyte white = 255;
2032 /* Make appropriate texture active */
2033 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2034 checkGLcall("glActiveTextureARB");
2036 /* Generate an opengl texture name */
2037 glGenTextures(1, &This->dummyTextureName[i]);
2038 checkGLcall("glGenTextures");
2039 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2041 /* Generate a dummy 2d texture (not using 1d because they cause many
2042 * DRI drivers fall back to sw) */
2043 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2044 checkGLcall("glBindTexture");
2046 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2047 checkGLcall("glTexImage2D");
2049 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2050 /* Reenable because if supported it is enabled by default */
2051 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2052 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2055 LEAVE_GL();
2058 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
2059 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2061 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2062 IWineD3DSwapChainImpl *swapchain = NULL;
2063 HRESULT hr;
2064 DWORD state;
2065 unsigned int i;
2067 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
2069 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2070 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2072 /* TODO: Test if OpenGL is compiled in and loaded */
2074 TRACE("(%p) : Creating stateblock\n", This);
2075 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2076 hr = IWineD3DDevice_CreateStateBlock(iface,
2077 WINED3DSBT_INIT,
2078 (IWineD3DStateBlock **)&This->stateBlock,
2079 NULL);
2080 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2081 WARN("Failed to create stateblock\n");
2082 goto err_out;
2084 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2085 This->updateStateBlock = This->stateBlock;
2086 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2088 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2089 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2091 This->NumberOfPalettes = 1;
2092 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2093 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2094 ERR("Out of memory!\n");
2095 goto err_out;
2097 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2098 if(!This->palettes[0]) {
2099 ERR("Out of memory!\n");
2100 goto err_out;
2102 for (i = 0; i < 256; ++i) {
2103 This->palettes[0][i].peRed = 0xFF;
2104 This->palettes[0][i].peGreen = 0xFF;
2105 This->palettes[0][i].peBlue = 0xFF;
2106 This->palettes[0][i].peFlags = 0xFF;
2108 This->currentPalette = 0;
2110 /* Initialize the texture unit mapping to a 1:1 mapping */
2111 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2112 if (state < GL_LIMITS(fragment_samplers)) {
2113 This->texUnitMap[state] = state;
2114 This->rev_tex_unit_map[state] = state;
2115 } else {
2116 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
2117 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
2121 /* Setup the implicit swapchain. This also initializes a context. */
2122 TRACE("Creating implicit swapchain\n");
2123 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2124 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2125 if (FAILED(hr))
2127 WARN("Failed to create implicit swapchain\n");
2128 goto err_out;
2131 This->NumberOfSwapChains = 1;
2132 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2133 if(!This->swapchains) {
2134 ERR("Out of memory!\n");
2135 goto err_out;
2137 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2139 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2140 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2141 This->render_targets[0] = swapchain->backBuffer[0];
2143 else {
2144 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2145 This->render_targets[0] = swapchain->frontBuffer;
2147 IWineD3DSurface_AddRef(This->render_targets[0]);
2149 /* Depth Stencil support */
2150 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2151 if (NULL != This->stencilBufferTarget) {
2152 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2155 hr = This->shader_backend->shader_alloc_private(iface);
2156 if(FAILED(hr)) {
2157 TRACE("Shader private data couldn't be allocated\n");
2158 goto err_out;
2160 hr = This->frag_pipe->alloc_private(iface);
2161 if(FAILED(hr)) {
2162 TRACE("Fragment pipeline private data couldn't be allocated\n");
2163 goto err_out;
2165 hr = This->blitter->alloc_private(iface);
2166 if(FAILED(hr)) {
2167 TRACE("Blitter private data couldn't be allocated\n");
2168 goto err_out;
2171 /* Set up some starting GL setup */
2173 /* Setup all the devices defaults */
2174 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2175 create_dummy_textures(This);
2177 ENTER_GL();
2179 /* Initialize the current view state */
2180 This->view_ident = 1;
2181 This->contexts[0]->last_was_rhw = 0;
2182 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2183 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2185 switch(wined3d_settings.offscreen_rendering_mode) {
2186 case ORM_FBO:
2187 case ORM_PBUFFER:
2188 This->offscreenBuffer = GL_BACK;
2189 break;
2191 case ORM_BACKBUFFER:
2193 if (context_get_current()->aux_buffers > 0)
2195 TRACE("Using auxilliary buffer for offscreen rendering\n");
2196 This->offscreenBuffer = GL_AUX0;
2197 } else {
2198 TRACE("Using back buffer for offscreen rendering\n");
2199 This->offscreenBuffer = GL_BACK;
2204 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2205 LEAVE_GL();
2207 /* Clear the screen */
2208 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2209 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2210 0x00, 1.0f, 0);
2212 This->d3d_initialized = TRUE;
2214 if(wined3d_settings.logo) {
2215 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2217 This->highest_dirty_ps_const = 0;
2218 This->highest_dirty_vs_const = 0;
2219 return WINED3D_OK;
2221 err_out:
2222 HeapFree(GetProcessHeap(), 0, This->render_targets);
2223 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2224 HeapFree(GetProcessHeap(), 0, This->swapchains);
2225 This->NumberOfSwapChains = 0;
2226 if(This->palettes) {
2227 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2228 HeapFree(GetProcessHeap(), 0, This->palettes);
2230 This->NumberOfPalettes = 0;
2231 if(swapchain) {
2232 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2234 if(This->stateBlock) {
2235 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2236 This->stateBlock = NULL;
2238 if (This->blit_priv) {
2239 This->blitter->free_private(iface);
2241 if (This->fragment_priv) {
2242 This->frag_pipe->free_private(iface);
2244 if (This->shader_priv) {
2245 This->shader_backend->shader_free_private(iface);
2247 return hr;
2250 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2251 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2253 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2254 IWineD3DSwapChainImpl *swapchain = NULL;
2255 HRESULT hr;
2257 /* Setup the implicit swapchain */
2258 TRACE("Creating implicit swapchain\n");
2259 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2260 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2261 if (FAILED(hr))
2263 WARN("Failed to create implicit swapchain\n");
2264 goto err_out;
2267 This->NumberOfSwapChains = 1;
2268 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2269 if(!This->swapchains) {
2270 ERR("Out of memory!\n");
2271 goto err_out;
2273 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2274 return WINED3D_OK;
2276 err_out:
2277 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2278 return hr;
2281 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2283 IWineD3DResource_UnLoad(resource);
2284 IWineD3DResource_Release(resource);
2285 return WINED3D_OK;
2288 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2289 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2290 int sampler;
2291 UINT i;
2292 TRACE("(%p)\n", This);
2294 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2296 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2297 * it was created. Thus make sure a context is active for the glDelete* calls
2299 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
2301 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2303 /* Unload resources */
2304 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2306 TRACE("Deleting high order patches\n");
2307 for(i = 0; i < PATCHMAP_SIZE; i++) {
2308 struct list *e1, *e2;
2309 struct WineD3DRectPatch *patch;
2310 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2311 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2312 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2316 /* Delete the palette conversion shader if it is around */
2317 if(This->paletteConversionShader) {
2318 ENTER_GL();
2319 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2320 LEAVE_GL();
2321 This->paletteConversionShader = 0;
2324 /* Delete the pbuffer context if there is any */
2325 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2327 /* Delete the mouse cursor texture */
2328 if(This->cursorTexture) {
2329 ENTER_GL();
2330 glDeleteTextures(1, &This->cursorTexture);
2331 LEAVE_GL();
2332 This->cursorTexture = 0;
2335 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2336 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2338 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2339 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2342 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2343 * private data, it might contain opengl pointers
2345 if(This->depth_blt_texture) {
2346 ENTER_GL();
2347 glDeleteTextures(1, &This->depth_blt_texture);
2348 LEAVE_GL();
2349 This->depth_blt_texture = 0;
2351 if (This->depth_blt_rb) {
2352 ENTER_GL();
2353 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2354 LEAVE_GL();
2355 This->depth_blt_rb = 0;
2356 This->depth_blt_rb_w = 0;
2357 This->depth_blt_rb_h = 0;
2360 /* Release the update stateblock */
2361 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2362 if(This->updateStateBlock != This->stateBlock)
2363 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2365 This->updateStateBlock = NULL;
2367 { /* because were not doing proper internal refcounts releasing the primary state block
2368 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2369 to set this->stateBlock = NULL; first */
2370 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2371 This->stateBlock = NULL;
2373 /* Release the stateblock */
2374 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2375 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2379 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2380 This->blitter->free_private(iface);
2381 This->frag_pipe->free_private(iface);
2382 This->shader_backend->shader_free_private(iface);
2384 /* Release the buffers (with sanity checks)*/
2385 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2386 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2387 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2388 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2390 This->stencilBufferTarget = NULL;
2392 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2393 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2394 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2396 TRACE("Setting rendertarget to NULL\n");
2397 This->render_targets[0] = NULL;
2399 if (This->auto_depth_stencil_buffer) {
2400 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2401 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2403 This->auto_depth_stencil_buffer = NULL;
2406 for(i=0; i < This->NumberOfSwapChains; i++) {
2407 TRACE("Releasing the implicit swapchain %d\n", i);
2408 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2409 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2413 HeapFree(GetProcessHeap(), 0, This->swapchains);
2414 This->swapchains = NULL;
2415 This->NumberOfSwapChains = 0;
2417 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2418 HeapFree(GetProcessHeap(), 0, This->palettes);
2419 This->palettes = NULL;
2420 This->NumberOfPalettes = 0;
2422 HeapFree(GetProcessHeap(), 0, This->render_targets);
2423 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2424 This->render_targets = NULL;
2425 This->draw_buffers = NULL;
2427 This->d3d_initialized = FALSE;
2428 return WINED3D_OK;
2431 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2432 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2433 unsigned int i;
2435 for(i=0; i < This->NumberOfSwapChains; i++) {
2436 TRACE("Releasing the implicit swapchain %d\n", i);
2437 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2438 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2442 HeapFree(GetProcessHeap(), 0, This->swapchains);
2443 This->swapchains = NULL;
2444 This->NumberOfSwapChains = 0;
2445 return WINED3D_OK;
2448 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2449 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2450 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2452 * There is no way to deactivate thread safety once it is enabled.
2454 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2455 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2457 /*For now just store the flag(needed in case of ddraw) */
2458 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2460 return;
2463 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2464 const WINED3DDISPLAYMODE* pMode) {
2465 DEVMODEW devmode;
2466 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2467 LONG ret;
2468 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &GLINFO_LOCATION);
2469 RECT clip_rc;
2471 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2473 /* Resize the screen even without a window:
2474 * The app could have unset it with SetCooperativeLevel, but not called
2475 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2476 * but we don't have any hwnd
2479 memset(&devmode, 0, sizeof(devmode));
2480 devmode.dmSize = sizeof(devmode);
2481 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2482 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2483 devmode.dmPelsWidth = pMode->Width;
2484 devmode.dmPelsHeight = pMode->Height;
2486 devmode.dmDisplayFrequency = pMode->RefreshRate;
2487 if (pMode->RefreshRate != 0) {
2488 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2491 /* Only change the mode if necessary */
2492 if( (This->ddraw_width == pMode->Width) &&
2493 (This->ddraw_height == pMode->Height) &&
2494 (This->ddraw_format == pMode->Format) &&
2495 (pMode->RefreshRate == 0) ) {
2496 return WINED3D_OK;
2499 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2500 if (ret != DISP_CHANGE_SUCCESSFUL) {
2501 if(devmode.dmDisplayFrequency != 0) {
2502 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2503 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2504 devmode.dmDisplayFrequency = 0;
2505 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2507 if(ret != DISP_CHANGE_SUCCESSFUL) {
2508 return WINED3DERR_NOTAVAILABLE;
2512 /* Store the new values */
2513 This->ddraw_width = pMode->Width;
2514 This->ddraw_height = pMode->Height;
2515 This->ddraw_format = pMode->Format;
2517 /* And finally clip mouse to our screen */
2518 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2519 ClipCursor(&clip_rc);
2521 return WINED3D_OK;
2524 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2525 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2526 *ppD3D= This->wineD3D;
2527 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2528 IWineD3D_AddRef(*ppD3D);
2529 return WINED3D_OK;
2532 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2533 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2535 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2536 (This->adapter->TextureRam/(1024*1024)),
2537 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2538 /* return simulated texture memory left */
2539 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2542 /*****
2543 * Get / Set Stream Source
2544 *****/
2545 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2546 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2548 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2549 IWineD3DBuffer *oldSrc;
2551 if (StreamNumber >= MAX_STREAMS) {
2552 WARN("Stream out of range %d\n", StreamNumber);
2553 return WINED3DERR_INVALIDCALL;
2554 } else if(OffsetInBytes & 0x3) {
2555 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2556 return WINED3DERR_INVALIDCALL;
2559 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2560 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2562 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2564 if(oldSrc == pStreamData &&
2565 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2566 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2567 TRACE("Application is setting the old values over, nothing to do\n");
2568 return WINED3D_OK;
2571 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2572 if (pStreamData) {
2573 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2574 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2577 /* Handle recording of state blocks */
2578 if (This->isRecordingState) {
2579 TRACE("Recording... not performing anything\n");
2580 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2581 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2582 return WINED3D_OK;
2585 if (pStreamData != NULL) {
2586 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2587 IWineD3DBuffer_AddRef(pStreamData);
2589 if (oldSrc != NULL) {
2590 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2591 IWineD3DBuffer_Release(oldSrc);
2594 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2596 return WINED3D_OK;
2599 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2600 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2604 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2605 This->stateBlock->streamSource[StreamNumber],
2606 This->stateBlock->streamOffset[StreamNumber],
2607 This->stateBlock->streamStride[StreamNumber]);
2609 if (StreamNumber >= MAX_STREAMS) {
2610 WARN("Stream out of range %d\n", StreamNumber);
2611 return WINED3DERR_INVALIDCALL;
2613 *pStream = This->stateBlock->streamSource[StreamNumber];
2614 *pStride = This->stateBlock->streamStride[StreamNumber];
2615 if (pOffset) {
2616 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2619 if (*pStream != NULL) {
2620 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2622 return WINED3D_OK;
2625 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2626 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2627 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2628 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2630 /* Verify input at least in d3d9 this is invalid*/
2631 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2632 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2633 return WINED3DERR_INVALIDCALL;
2635 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2636 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2637 return WINED3DERR_INVALIDCALL;
2639 if( Divider == 0 ){
2640 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2641 return WINED3DERR_INVALIDCALL;
2644 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2645 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2647 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2648 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2650 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2651 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2652 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2655 return WINED3D_OK;
2658 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2659 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2661 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2662 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2664 TRACE("(%p) : returning %d\n", This, *Divider);
2666 return WINED3D_OK;
2669 /*****
2670 * Get / Set & Multiply Transform
2671 *****/
2672 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2673 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2675 /* Most of this routine, comments included copied from ddraw tree initially: */
2676 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2678 /* Handle recording of state blocks */
2679 if (This->isRecordingState) {
2680 TRACE("Recording... not performing anything\n");
2681 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2682 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2683 return WINED3D_OK;
2687 * If the new matrix is the same as the current one,
2688 * we cut off any further processing. this seems to be a reasonable
2689 * optimization because as was noticed, some apps (warcraft3 for example)
2690 * tend towards setting the same matrix repeatedly for some reason.
2692 * From here on we assume that the new matrix is different, wherever it matters.
2694 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2695 TRACE("The app is setting the same matrix over again\n");
2696 return WINED3D_OK;
2697 } else {
2698 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2702 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2703 where ViewMat = Camera space, WorldMat = world space.
2705 In OpenGL, camera and world space is combined into GL_MODELVIEW
2706 matrix. The Projection matrix stay projection matrix.
2709 /* Capture the times we can just ignore the change for now */
2710 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2711 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2712 /* Handled by the state manager */
2715 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2716 return WINED3D_OK;
2719 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2720 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2721 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2722 *pMatrix = This->stateBlock->transforms[State];
2723 return WINED3D_OK;
2726 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2727 const WINED3DMATRIX *mat = NULL;
2728 WINED3DMATRIX temp;
2730 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2731 * below means it will be recorded in a state block change, but it
2732 * works regardless where it is recorded.
2733 * If this is found to be wrong, change to StateBlock.
2735 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2736 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2738 if (State <= HIGHEST_TRANSFORMSTATE)
2740 mat = &This->updateStateBlock->transforms[State];
2741 } else {
2742 FIXME("Unhandled transform state!!\n");
2745 multiply_matrix(&temp, mat, pMatrix);
2747 /* Apply change via set transform - will reapply to eg. lights this way */
2748 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2751 /*****
2752 * Get / Set Light
2753 *****/
2754 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2755 you can reference any indexes you want as long as that number max are enabled at any
2756 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2757 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2758 but when recording, just build a chain pretty much of commands to be replayed. */
2760 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2761 float rho;
2762 PLIGHTINFOEL *object = NULL;
2763 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2764 struct list *e;
2766 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2767 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2769 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2770 * the gl driver.
2772 if(!pLight) {
2773 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2774 return WINED3DERR_INVALIDCALL;
2777 switch(pLight->Type) {
2778 case WINED3DLIGHT_POINT:
2779 case WINED3DLIGHT_SPOT:
2780 case WINED3DLIGHT_PARALLELPOINT:
2781 case WINED3DLIGHT_GLSPOT:
2782 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2783 * most wanted
2785 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2787 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2788 return WINED3DERR_INVALIDCALL;
2790 break;
2792 case WINED3DLIGHT_DIRECTIONAL:
2793 /* Ignores attenuation */
2794 break;
2796 default:
2797 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2798 return WINED3DERR_INVALIDCALL;
2801 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2802 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2803 if(object->OriginalIndex == Index) break;
2804 object = NULL;
2807 if(!object) {
2808 TRACE("Adding new light\n");
2809 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2810 if(!object) {
2811 ERR("Out of memory error when allocating a light\n");
2812 return E_OUTOFMEMORY;
2814 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2815 object->glIndex = -1;
2816 object->OriginalIndex = Index;
2817 object->changed = TRUE;
2820 /* Initialize the object */
2821 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,
2822 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2823 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2824 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2825 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2826 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2827 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2829 /* Save away the information */
2830 object->OriginalParms = *pLight;
2832 switch (pLight->Type) {
2833 case WINED3DLIGHT_POINT:
2834 /* Position */
2835 object->lightPosn[0] = pLight->Position.x;
2836 object->lightPosn[1] = pLight->Position.y;
2837 object->lightPosn[2] = pLight->Position.z;
2838 object->lightPosn[3] = 1.0f;
2839 object->cutoff = 180.0f;
2840 /* FIXME: Range */
2841 break;
2843 case WINED3DLIGHT_DIRECTIONAL:
2844 /* Direction */
2845 object->lightPosn[0] = -pLight->Direction.x;
2846 object->lightPosn[1] = -pLight->Direction.y;
2847 object->lightPosn[2] = -pLight->Direction.z;
2848 object->lightPosn[3] = 0.0f;
2849 object->exponent = 0.0f;
2850 object->cutoff = 180.0f;
2851 break;
2853 case WINED3DLIGHT_SPOT:
2854 /* Position */
2855 object->lightPosn[0] = pLight->Position.x;
2856 object->lightPosn[1] = pLight->Position.y;
2857 object->lightPosn[2] = pLight->Position.z;
2858 object->lightPosn[3] = 1.0f;
2860 /* Direction */
2861 object->lightDirn[0] = pLight->Direction.x;
2862 object->lightDirn[1] = pLight->Direction.y;
2863 object->lightDirn[2] = pLight->Direction.z;
2864 object->lightDirn[3] = 1.0f;
2867 * opengl-ish and d3d-ish spot lights use too different models for the
2868 * light "intensity" as a function of the angle towards the main light direction,
2869 * so we only can approximate very roughly.
2870 * however spot lights are rather rarely used in games (if ever used at all).
2871 * furthermore if still used, probably nobody pays attention to such details.
2873 if (pLight->Falloff == 0) {
2874 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2875 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2876 * will always be 1.0 for both of them, and we don't have to care for the
2877 * rest of the rather complex calculation
2879 object->exponent = 0.0f;
2880 } else {
2881 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2882 if (rho < 0.0001f) rho = 0.0001f;
2883 object->exponent = -0.3f/logf(cosf(rho/2));
2885 if (object->exponent > 128.0f)
2887 object->exponent = 128.0f;
2889 object->cutoff = pLight->Phi*90/M_PI;
2891 /* FIXME: Range */
2892 break;
2894 default:
2895 FIXME("Unrecognized light type %d\n", pLight->Type);
2898 /* Update the live definitions if the light is currently assigned a glIndex */
2899 if (object->glIndex != -1 && !This->isRecordingState) {
2900 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2902 return WINED3D_OK;
2905 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2906 PLIGHTINFOEL *lightInfo = NULL;
2907 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2908 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2909 struct list *e;
2910 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2912 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2913 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2914 if(lightInfo->OriginalIndex == Index) break;
2915 lightInfo = NULL;
2918 if (lightInfo == NULL) {
2919 TRACE("Light information requested but light not defined\n");
2920 return WINED3DERR_INVALIDCALL;
2923 *pLight = lightInfo->OriginalParms;
2924 return WINED3D_OK;
2927 /*****
2928 * Get / Set Light Enable
2929 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2930 *****/
2931 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2932 PLIGHTINFOEL *lightInfo = NULL;
2933 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2934 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2935 struct list *e;
2936 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2938 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2939 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2940 if(lightInfo->OriginalIndex == Index) break;
2941 lightInfo = NULL;
2943 TRACE("Found light: %p\n", lightInfo);
2945 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2946 if (lightInfo == NULL) {
2948 TRACE("Light enabled requested but light not defined, so defining one!\n");
2949 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2951 /* Search for it again! Should be fairly quick as near head of list */
2952 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2953 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2954 if(lightInfo->OriginalIndex == Index) break;
2955 lightInfo = NULL;
2957 if (lightInfo == NULL) {
2958 FIXME("Adding default lights has failed dismally\n");
2959 return WINED3DERR_INVALIDCALL;
2963 lightInfo->enabledChanged = TRUE;
2964 if(!Enable) {
2965 if(lightInfo->glIndex != -1) {
2966 if(!This->isRecordingState) {
2967 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2970 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2971 lightInfo->glIndex = -1;
2972 } else {
2973 TRACE("Light already disabled, nothing to do\n");
2975 lightInfo->enabled = FALSE;
2976 } else {
2977 lightInfo->enabled = TRUE;
2978 if (lightInfo->glIndex != -1) {
2979 /* nop */
2980 TRACE("Nothing to do as light was enabled\n");
2981 } else {
2982 int i;
2983 /* Find a free gl light */
2984 for(i = 0; i < This->maxConcurrentLights; i++) {
2985 if(This->updateStateBlock->activeLights[i] == NULL) {
2986 This->updateStateBlock->activeLights[i] = lightInfo;
2987 lightInfo->glIndex = i;
2988 break;
2991 if(lightInfo->glIndex == -1) {
2992 /* Our tests show that Windows returns D3D_OK in this situation, even with
2993 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2994 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2995 * as well for those lights.
2997 * TODO: Test how this affects rendering
2999 WARN("Too many concurrently active lights\n");
3000 return WINED3D_OK;
3003 /* i == lightInfo->glIndex */
3004 if(!This->isRecordingState) {
3005 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3010 return WINED3D_OK;
3013 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3015 PLIGHTINFOEL *lightInfo = NULL;
3016 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3017 struct list *e;
3018 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3019 TRACE("(%p) : for idx(%d)\n", This, Index);
3021 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3022 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3023 if(lightInfo->OriginalIndex == Index) break;
3024 lightInfo = NULL;
3027 if (lightInfo == NULL) {
3028 TRACE("Light enabled state requested but light not defined\n");
3029 return WINED3DERR_INVALIDCALL;
3031 /* true is 128 according to SetLightEnable */
3032 *pEnable = lightInfo->enabled ? 128 : 0;
3033 return WINED3D_OK;
3036 /*****
3037 * Get / Set Clip Planes
3038 *****/
3039 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3040 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3041 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3043 /* Validate Index */
3044 if (Index >= GL_LIMITS(clipplanes)) {
3045 TRACE("Application has requested clipplane this device doesn't support\n");
3046 return WINED3DERR_INVALIDCALL;
3049 This->updateStateBlock->changed.clipplane |= 1 << Index;
3051 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3052 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3053 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3054 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3055 TRACE("Application is setting old values over, nothing to do\n");
3056 return WINED3D_OK;
3059 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3060 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3061 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3062 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3064 /* Handle recording of state blocks */
3065 if (This->isRecordingState) {
3066 TRACE("Recording... not performing anything\n");
3067 return WINED3D_OK;
3070 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3072 return WINED3D_OK;
3075 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3076 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3077 TRACE("(%p) : for idx %d\n", This, Index);
3079 /* Validate Index */
3080 if (Index >= GL_LIMITS(clipplanes)) {
3081 TRACE("Application has requested clipplane this device doesn't support\n");
3082 return WINED3DERR_INVALIDCALL;
3085 pPlane[0] = This->stateBlock->clipplane[Index][0];
3086 pPlane[1] = This->stateBlock->clipplane[Index][1];
3087 pPlane[2] = This->stateBlock->clipplane[Index][2];
3088 pPlane[3] = This->stateBlock->clipplane[Index][3];
3089 return WINED3D_OK;
3092 /*****
3093 * Get / Set Clip Plane Status
3094 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3095 *****/
3096 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3097 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3098 FIXME("(%p) : stub\n", This);
3099 if (NULL == pClipStatus) {
3100 return WINED3DERR_INVALIDCALL;
3102 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3103 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3104 return WINED3D_OK;
3107 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3109 FIXME("(%p) : stub\n", This);
3110 if (NULL == pClipStatus) {
3111 return WINED3DERR_INVALIDCALL;
3113 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3114 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3115 return WINED3D_OK;
3118 /*****
3119 * Get / Set Material
3120 *****/
3121 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3122 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3124 This->updateStateBlock->changed.material = TRUE;
3125 This->updateStateBlock->material = *pMaterial;
3127 /* Handle recording of state blocks */
3128 if (This->isRecordingState) {
3129 TRACE("Recording... not performing anything\n");
3130 return WINED3D_OK;
3133 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3134 return WINED3D_OK;
3137 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3139 *pMaterial = This->updateStateBlock->material;
3140 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3141 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3142 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3143 pMaterial->Ambient.b, pMaterial->Ambient.a);
3144 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3145 pMaterial->Specular.b, pMaterial->Specular.a);
3146 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3147 pMaterial->Emissive.b, pMaterial->Emissive.a);
3148 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3150 return WINED3D_OK;
3153 /*****
3154 * Get / Set Indices
3155 *****/
3156 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DBuffer* pIndexData, WINED3DFORMAT fmt) {
3157 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3158 IWineD3DBuffer *oldIdxs;
3160 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3161 oldIdxs = This->updateStateBlock->pIndexData;
3163 This->updateStateBlock->changed.indices = TRUE;
3164 This->updateStateBlock->pIndexData = pIndexData;
3165 This->updateStateBlock->IndexFmt = fmt;
3167 /* Handle recording of state blocks */
3168 if (This->isRecordingState) {
3169 TRACE("Recording... not performing anything\n");
3170 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
3171 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
3172 return WINED3D_OK;
3175 if(oldIdxs != pIndexData) {
3176 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3177 if(pIndexData) {
3178 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
3179 IWineD3DBuffer_AddRef(pIndexData);
3181 if(oldIdxs) {
3182 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
3183 IWineD3DBuffer_Release(oldIdxs);
3187 return WINED3D_OK;
3190 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DBuffer** ppIndexData) {
3191 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3193 *ppIndexData = This->stateBlock->pIndexData;
3195 /* up ref count on ppindexdata */
3196 if (*ppIndexData) {
3197 IWineD3DBuffer_AddRef(*ppIndexData);
3198 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3199 }else{
3200 TRACE("(%p) No index data set\n", This);
3202 TRACE("Returning %p\n", *ppIndexData);
3204 return WINED3D_OK;
3207 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3208 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3210 TRACE("(%p)->(%d)\n", This, BaseIndex);
3212 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3213 TRACE("Application is setting the old value over, nothing to do\n");
3214 return WINED3D_OK;
3217 This->updateStateBlock->baseVertexIndex = BaseIndex;
3219 if (This->isRecordingState) {
3220 TRACE("Recording... not performing anything\n");
3221 return WINED3D_OK;
3223 /* The base vertex index affects the stream sources */
3224 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3225 return WINED3D_OK;
3228 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3229 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3230 TRACE("(%p) : base_index %p\n", This, base_index);
3232 *base_index = This->stateBlock->baseVertexIndex;
3234 TRACE("Returning %u\n", *base_index);
3236 return WINED3D_OK;
3239 /*****
3240 * Get / Set Viewports
3241 *****/
3242 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3243 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3245 TRACE("(%p)\n", This);
3246 This->updateStateBlock->changed.viewport = TRUE;
3247 This->updateStateBlock->viewport = *pViewport;
3249 /* Handle recording of state blocks */
3250 if (This->isRecordingState) {
3251 TRACE("Recording... not performing anything\n");
3252 return WINED3D_OK;
3255 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3256 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3258 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3259 return WINED3D_OK;
3263 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3264 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3265 TRACE("(%p)\n", This);
3266 *pViewport = This->stateBlock->viewport;
3267 return WINED3D_OK;
3270 /*****
3271 * Get / Set Render States
3272 * TODO: Verify against dx9 definitions
3273 *****/
3274 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3276 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3277 DWORD oldValue = This->stateBlock->renderState[State];
3279 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3281 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3282 This->updateStateBlock->renderState[State] = Value;
3284 /* Handle recording of state blocks */
3285 if (This->isRecordingState) {
3286 TRACE("Recording... not performing anything\n");
3287 return WINED3D_OK;
3290 /* Compared here and not before the assignment to allow proper stateblock recording */
3291 if(Value == oldValue) {
3292 TRACE("Application is setting the old value over, nothing to do\n");
3293 } else {
3294 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3297 return WINED3D_OK;
3300 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3301 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3302 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3303 *pValue = This->stateBlock->renderState[State];
3304 return WINED3D_OK;
3307 /*****
3308 * Get / Set Sampler States
3309 * TODO: Verify against dx9 definitions
3310 *****/
3312 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3313 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3314 DWORD oldValue;
3316 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3317 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3319 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3320 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3323 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3324 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3325 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3328 * SetSampler is designed to allow for more than the standard up to 8 textures
3329 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3330 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3332 * http://developer.nvidia.com/object/General_FAQ.html#t6
3334 * There are two new settings for GForce
3335 * the sampler one:
3336 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3337 * and the texture one:
3338 * GL_MAX_TEXTURE_COORDS_ARB.
3339 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3340 ******************/
3342 oldValue = This->stateBlock->samplerState[Sampler][Type];
3343 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3344 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3346 /* Handle recording of state blocks */
3347 if (This->isRecordingState) {
3348 TRACE("Recording... not performing anything\n");
3349 return WINED3D_OK;
3352 if(oldValue == Value) {
3353 TRACE("Application is setting the old value over, nothing to do\n");
3354 return WINED3D_OK;
3357 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3359 return WINED3D_OK;
3362 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3363 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3365 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3366 This, Sampler, debug_d3dsamplerstate(Type), Type);
3368 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3369 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3372 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3373 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3374 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3376 *Value = This->stateBlock->samplerState[Sampler][Type];
3377 TRACE("(%p) : Returning %#x\n", This, *Value);
3379 return WINED3D_OK;
3382 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3383 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3385 This->updateStateBlock->changed.scissorRect = TRUE;
3386 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3387 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3388 return WINED3D_OK;
3390 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3392 if(This->isRecordingState) {
3393 TRACE("Recording... not performing anything\n");
3394 return WINED3D_OK;
3397 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3399 return WINED3D_OK;
3402 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3403 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3405 *pRect = This->updateStateBlock->scissorRect;
3406 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3407 return WINED3D_OK;
3410 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3411 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3412 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3414 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3416 This->updateStateBlock->vertexDecl = pDecl;
3417 This->updateStateBlock->changed.vertexDecl = TRUE;
3419 if (This->isRecordingState) {
3420 TRACE("Recording... not performing anything\n");
3421 return WINED3D_OK;
3422 } else if(pDecl == oldDecl) {
3423 /* Checked after the assignment to allow proper stateblock recording */
3424 TRACE("Application is setting the old declaration over, nothing to do\n");
3425 return WINED3D_OK;
3428 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3429 return WINED3D_OK;
3432 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3433 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3435 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3437 *ppDecl = This->stateBlock->vertexDecl;
3438 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3439 return WINED3D_OK;
3442 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3443 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3444 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3446 This->updateStateBlock->vertexShader = pShader;
3447 This->updateStateBlock->changed.vertexShader = TRUE;
3449 if (This->isRecordingState) {
3450 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3451 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3452 TRACE("Recording... not performing anything\n");
3453 return WINED3D_OK;
3454 } else if(oldShader == pShader) {
3455 /* Checked here to allow proper stateblock recording */
3456 TRACE("App is setting the old shader over, nothing to do\n");
3457 return WINED3D_OK;
3460 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3461 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3462 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3464 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3466 return WINED3D_OK;
3469 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3470 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3472 if (NULL == ppShader) {
3473 return WINED3DERR_INVALIDCALL;
3475 *ppShader = This->stateBlock->vertexShader;
3476 if( NULL != *ppShader)
3477 IWineD3DVertexShader_AddRef(*ppShader);
3479 TRACE("(%p) : returning %p\n", This, *ppShader);
3480 return WINED3D_OK;
3483 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3484 IWineD3DDevice *iface,
3485 UINT start,
3486 CONST BOOL *srcData,
3487 UINT count) {
3489 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3490 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3492 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3493 iface, srcData, start, count);
3495 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3497 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3498 for (i = 0; i < cnt; i++)
3499 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3501 for (i = start; i < cnt + start; ++i) {
3502 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3505 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3507 return WINED3D_OK;
3510 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3511 IWineD3DDevice *iface,
3512 UINT start,
3513 BOOL *dstData,
3514 UINT count) {
3516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3517 int cnt = min(count, MAX_CONST_B - start);
3519 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3520 iface, dstData, start, count);
3522 if (dstData == NULL || cnt < 0)
3523 return WINED3DERR_INVALIDCALL;
3525 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3526 return WINED3D_OK;
3529 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3530 IWineD3DDevice *iface,
3531 UINT start,
3532 CONST int *srcData,
3533 UINT count) {
3535 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3536 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3538 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3539 iface, srcData, start, count);
3541 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3543 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3544 for (i = 0; i < cnt; i++)
3545 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3546 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3548 for (i = start; i < cnt + start; ++i) {
3549 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3552 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3554 return WINED3D_OK;
3557 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3558 IWineD3DDevice *iface,
3559 UINT start,
3560 int *dstData,
3561 UINT count) {
3563 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3564 int cnt = min(count, MAX_CONST_I - start);
3566 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3567 iface, dstData, start, count);
3569 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3570 return WINED3DERR_INVALIDCALL;
3572 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3573 return WINED3D_OK;
3576 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3577 IWineD3DDevice *iface,
3578 UINT start,
3579 CONST float *srcData,
3580 UINT count) {
3582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3583 UINT i;
3585 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3586 iface, srcData, start, count);
3588 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3589 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3590 return WINED3DERR_INVALIDCALL;
3592 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3593 if(TRACE_ON(d3d)) {
3594 for (i = 0; i < count; i++)
3595 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3596 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3599 if (!This->isRecordingState)
3601 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3602 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3605 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3606 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3608 return WINED3D_OK;
3611 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3612 IWineD3DDevice *iface,
3613 UINT start,
3614 float *dstData,
3615 UINT count) {
3617 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3618 int cnt = min(count, This->d3d_vshader_constantF - start);
3620 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3621 iface, dstData, start, count);
3623 if (dstData == NULL || cnt < 0)
3624 return WINED3DERR_INVALIDCALL;
3626 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3627 return WINED3D_OK;
3630 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3631 DWORD i;
3632 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3634 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3638 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3640 DWORD i = This->rev_tex_unit_map[unit];
3641 DWORD j = This->texUnitMap[stage];
3643 This->texUnitMap[stage] = unit;
3644 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3646 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3649 This->rev_tex_unit_map[unit] = stage;
3650 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3652 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3656 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3657 int i;
3659 This->fixed_function_usage_map = 0;
3660 for (i = 0; i < MAX_TEXTURES; ++i) {
3661 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3662 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3663 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3664 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3665 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3666 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3667 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3668 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3670 if (color_op == WINED3DTOP_DISABLE) {
3671 /* Not used, and disable higher stages */
3672 break;
3675 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3676 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3677 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3678 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3679 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3680 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3681 This->fixed_function_usage_map |= (1 << i);
3684 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3685 This->fixed_function_usage_map |= (1 << (i + 1));
3690 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3691 unsigned int i, tex;
3692 WORD ffu_map;
3694 device_update_fixed_function_usage_map(This);
3695 ffu_map = This->fixed_function_usage_map;
3697 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3698 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3699 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3701 if (!(ffu_map & 1)) continue;
3703 if (This->texUnitMap[i] != i) {
3704 device_map_stage(This, i, i);
3705 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3706 markTextureStagesDirty(This, i);
3709 return;
3712 /* Now work out the mapping */
3713 tex = 0;
3714 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3716 if (!(ffu_map & 1)) continue;
3718 if (This->texUnitMap[i] != tex) {
3719 device_map_stage(This, i, tex);
3720 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3721 markTextureStagesDirty(This, i);
3724 ++tex;
3728 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3729 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3730 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3731 unsigned int i;
3733 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3734 if (sampler_type[i] && This->texUnitMap[i] != i)
3736 device_map_stage(This, i, i);
3737 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3738 if (i < MAX_TEXTURES) {
3739 markTextureStagesDirty(This, i);
3745 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3746 const DWORD *vshader_sampler_tokens, DWORD unit)
3748 DWORD current_mapping = This->rev_tex_unit_map[unit];
3750 /* Not currently used */
3751 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3753 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3754 /* Used by a fragment sampler */
3756 if (!pshader_sampler_tokens) {
3757 /* No pixel shader, check fixed function */
3758 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3761 /* Pixel shader, check the shader's sampler map */
3762 return !pshader_sampler_tokens[current_mapping];
3765 /* Used by a vertex sampler */
3766 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3769 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3770 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3771 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3772 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3773 int start = min(MAX_COMBINED_SAMPLERS, GL_LIMITS(combined_samplers)) - 1;
3774 int i;
3776 if (ps) {
3777 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3779 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3780 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3781 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3784 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3785 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3786 if (vshader_sampler_type[i])
3788 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3790 /* Already mapped somewhere */
3791 continue;
3794 while (start >= 0) {
3795 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3797 device_map_stage(This, vsampler_idx, start);
3798 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3800 --start;
3801 break;
3804 --start;
3810 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3811 BOOL vs = use_vs(This->stateBlock);
3812 BOOL ps = use_ps(This->stateBlock);
3814 * Rules are:
3815 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3816 * that would be really messy and require shader recompilation
3817 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3818 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3820 if (ps) {
3821 device_map_psamplers(This);
3822 } else {
3823 device_map_fixed_function_samplers(This);
3826 if (vs) {
3827 device_map_vsamplers(This, ps);
3831 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3832 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3833 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3834 This->updateStateBlock->pixelShader = pShader;
3835 This->updateStateBlock->changed.pixelShader = TRUE;
3837 /* Handle recording of state blocks */
3838 if (This->isRecordingState) {
3839 TRACE("Recording... not performing anything\n");
3842 if (This->isRecordingState) {
3843 TRACE("Recording... not performing anything\n");
3844 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3845 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3846 return WINED3D_OK;
3849 if(pShader == oldShader) {
3850 TRACE("App is setting the old pixel shader over, nothing to do\n");
3851 return WINED3D_OK;
3854 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3855 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3857 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3858 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3860 return WINED3D_OK;
3863 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3864 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3866 if (NULL == ppShader) {
3867 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3868 return WINED3DERR_INVALIDCALL;
3871 *ppShader = This->stateBlock->pixelShader;
3872 if (NULL != *ppShader) {
3873 IWineD3DPixelShader_AddRef(*ppShader);
3875 TRACE("(%p) : returning %p\n", This, *ppShader);
3876 return WINED3D_OK;
3879 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3880 IWineD3DDevice *iface,
3881 UINT start,
3882 CONST BOOL *srcData,
3883 UINT count) {
3885 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3886 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3888 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3889 iface, srcData, start, count);
3891 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3893 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3894 for (i = 0; i < cnt; i++)
3895 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3897 for (i = start; i < cnt + start; ++i) {
3898 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3901 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3903 return WINED3D_OK;
3906 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3907 IWineD3DDevice *iface,
3908 UINT start,
3909 BOOL *dstData,
3910 UINT count) {
3912 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3913 int cnt = min(count, MAX_CONST_B - start);
3915 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3916 iface, dstData, start, count);
3918 if (dstData == NULL || cnt < 0)
3919 return WINED3DERR_INVALIDCALL;
3921 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3922 return WINED3D_OK;
3925 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3926 IWineD3DDevice *iface,
3927 UINT start,
3928 CONST int *srcData,
3929 UINT count) {
3931 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3932 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3934 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3935 iface, srcData, start, count);
3937 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3939 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3940 for (i = 0; i < cnt; i++)
3941 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3942 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3944 for (i = start; i < cnt + start; ++i) {
3945 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3948 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3950 return WINED3D_OK;
3953 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3954 IWineD3DDevice *iface,
3955 UINT start,
3956 int *dstData,
3957 UINT count) {
3959 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3960 int cnt = min(count, MAX_CONST_I - start);
3962 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3963 iface, dstData, start, count);
3965 if (dstData == NULL || cnt < 0)
3966 return WINED3DERR_INVALIDCALL;
3968 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3969 return WINED3D_OK;
3972 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3973 IWineD3DDevice *iface,
3974 UINT start,
3975 CONST float *srcData,
3976 UINT count) {
3978 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3979 UINT i;
3981 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3982 iface, srcData, start, count);
3984 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3985 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3986 return WINED3DERR_INVALIDCALL;
3988 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3989 if(TRACE_ON(d3d)) {
3990 for (i = 0; i < count; i++)
3991 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3992 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3995 if (!This->isRecordingState)
3997 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3998 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4001 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
4002 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
4004 return WINED3D_OK;
4007 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4008 IWineD3DDevice *iface,
4009 UINT start,
4010 float *dstData,
4011 UINT count) {
4013 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4014 int cnt = min(count, This->d3d_pshader_constantF - start);
4016 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4017 iface, dstData, start, count);
4019 if (dstData == NULL || cnt < 0)
4020 return WINED3DERR_INVALIDCALL;
4022 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4023 return WINED3D_OK;
4026 /* Context activation is done by the caller. */
4027 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4028 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4029 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
4030 DWORD DestFVF)
4032 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4033 unsigned int i;
4034 WINED3DVIEWPORT vp;
4035 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4036 BOOL doClip;
4037 DWORD numTextures;
4039 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
4041 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4044 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
4046 ERR("Source has no position mask\n");
4047 return WINED3DERR_INVALIDCALL;
4050 /* We might access VBOs from this code, so hold the lock */
4051 ENTER_GL();
4053 if (dest->resource.allocatedMemory == NULL) {
4054 buffer_get_sysmem(dest);
4057 /* Get a pointer into the destination vbo(create one if none exists) and
4058 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4060 if (!dest->buffer_object && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT))
4062 dest->flags |= WINED3D_BUFFER_CREATEBO;
4063 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
4066 if (dest->buffer_object)
4068 unsigned char extrabytes = 0;
4069 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4070 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4071 * this may write 4 extra bytes beyond the area that should be written
4073 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4074 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4075 if(!dest_conv_addr) {
4076 ERR("Out of memory\n");
4077 /* Continue without storing converted vertices */
4079 dest_conv = dest_conv_addr;
4082 /* Should I clip?
4083 * a) WINED3DRS_CLIPPING is enabled
4084 * b) WINED3DVOP_CLIP is passed
4086 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4087 static BOOL warned = FALSE;
4089 * The clipping code is not quite correct. Some things need
4090 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4091 * so disable clipping for now.
4092 * (The graphics in Half-Life are broken, and my processvertices
4093 * test crashes with IDirect3DDevice3)
4094 doClip = TRUE;
4096 doClip = FALSE;
4097 if(!warned) {
4098 warned = TRUE;
4099 FIXME("Clipping is broken and disabled for now\n");
4101 } else doClip = FALSE;
4102 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4104 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4105 WINED3DTS_VIEW,
4106 &view_mat);
4107 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4108 WINED3DTS_PROJECTION,
4109 &proj_mat);
4110 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4111 WINED3DTS_WORLDMATRIX(0),
4112 &world_mat);
4114 TRACE("View mat:\n");
4115 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);
4116 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);
4117 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);
4118 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);
4120 TRACE("Proj mat:\n");
4121 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);
4122 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);
4123 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);
4124 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);
4126 TRACE("World mat:\n");
4127 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);
4128 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);
4129 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);
4130 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);
4132 /* Get the viewport */
4133 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4134 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4135 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4137 multiply_matrix(&mat,&view_mat,&world_mat);
4138 multiply_matrix(&mat,&proj_mat,&mat);
4140 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4142 for (i = 0; i < dwCount; i+= 1) {
4143 unsigned int tex_index;
4145 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4146 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4147 /* The position first */
4148 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
4149 const float *p = (const float *)(element->data + i * element->stride);
4150 float x, y, z, rhw;
4151 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4153 /* Multiplication with world, view and projection matrix */
4154 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);
4155 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);
4156 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);
4157 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);
4159 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4161 /* WARNING: The following things are taken from d3d7 and were not yet checked
4162 * against d3d8 or d3d9!
4165 /* Clipping conditions: From msdn
4167 * A vertex is clipped if it does not match the following requirements
4168 * -rhw < x <= rhw
4169 * -rhw < y <= rhw
4170 * 0 < z <= rhw
4171 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4173 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4174 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4178 if( !doClip ||
4179 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4180 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4181 ( rhw > eps ) ) ) {
4183 /* "Normal" viewport transformation (not clipped)
4184 * 1) The values are divided by rhw
4185 * 2) The y axis is negative, so multiply it with -1
4186 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4187 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4188 * 4) Multiply x with Width/2 and add Width/2
4189 * 5) The same for the height
4190 * 6) Add the viewpoint X and Y to the 2D coordinates and
4191 * The minimum Z value to z
4192 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4194 * Well, basically it's simply a linear transformation into viewport
4195 * coordinates
4198 x /= rhw;
4199 y /= rhw;
4200 z /= rhw;
4202 y *= -1;
4204 x *= vp.Width / 2;
4205 y *= vp.Height / 2;
4206 z *= vp.MaxZ - vp.MinZ;
4208 x += vp.Width / 2 + vp.X;
4209 y += vp.Height / 2 + vp.Y;
4210 z += vp.MinZ;
4212 rhw = 1 / rhw;
4213 } else {
4214 /* That vertex got clipped
4215 * Contrary to OpenGL it is not dropped completely, it just
4216 * undergoes a different calculation.
4218 TRACE("Vertex got clipped\n");
4219 x += rhw;
4220 y += rhw;
4222 x /= 2;
4223 y /= 2;
4225 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4226 * outside of the main vertex buffer memory. That needs some more
4227 * investigation...
4231 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4234 ( (float *) dest_ptr)[0] = x;
4235 ( (float *) dest_ptr)[1] = y;
4236 ( (float *) dest_ptr)[2] = z;
4237 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4239 dest_ptr += 3 * sizeof(float);
4241 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4242 dest_ptr += sizeof(float);
4245 if(dest_conv) {
4246 float w = 1 / rhw;
4247 ( (float *) dest_conv)[0] = x * w;
4248 ( (float *) dest_conv)[1] = y * w;
4249 ( (float *) dest_conv)[2] = z * w;
4250 ( (float *) dest_conv)[3] = w;
4252 dest_conv += 3 * sizeof(float);
4254 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4255 dest_conv += sizeof(float);
4259 if (DestFVF & WINED3DFVF_PSIZE) {
4260 dest_ptr += sizeof(DWORD);
4261 if(dest_conv) dest_conv += sizeof(DWORD);
4263 if (DestFVF & WINED3DFVF_NORMAL) {
4264 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4265 const float *normal = (const float *)(element->data + i * element->stride);
4266 /* AFAIK this should go into the lighting information */
4267 FIXME("Didn't expect the destination to have a normal\n");
4268 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4269 if(dest_conv) {
4270 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4274 if (DestFVF & WINED3DFVF_DIFFUSE) {
4275 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4276 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4277 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4279 static BOOL warned = FALSE;
4281 if(!warned) {
4282 ERR("No diffuse color in source, but destination has one\n");
4283 warned = TRUE;
4286 *( (DWORD *) dest_ptr) = 0xffffffff;
4287 dest_ptr += sizeof(DWORD);
4289 if(dest_conv) {
4290 *( (DWORD *) dest_conv) = 0xffffffff;
4291 dest_conv += sizeof(DWORD);
4294 else {
4295 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4296 if(dest_conv) {
4297 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4298 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4299 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4300 dest_conv += sizeof(DWORD);
4305 if (DestFVF & WINED3DFVF_SPECULAR) {
4306 /* What's the color value in the feedback buffer? */
4307 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4308 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4309 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4311 static BOOL warned = FALSE;
4313 if(!warned) {
4314 ERR("No specular color in source, but destination has one\n");
4315 warned = TRUE;
4318 *( (DWORD *) dest_ptr) = 0xFF000000;
4319 dest_ptr += sizeof(DWORD);
4321 if(dest_conv) {
4322 *( (DWORD *) dest_conv) = 0xFF000000;
4323 dest_conv += sizeof(DWORD);
4326 else {
4327 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4328 if(dest_conv) {
4329 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4330 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4331 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4332 dest_conv += sizeof(DWORD);
4337 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4338 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4339 const float *tex_coord = (const float *)(element->data + i * element->stride);
4340 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4342 ERR("No source texture, but destination requests one\n");
4343 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4344 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4346 else {
4347 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4348 if(dest_conv) {
4349 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4355 if(dest_conv) {
4356 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4357 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4358 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4359 dwCount * get_flexible_vertex_size(DestFVF),
4360 dest_conv_addr));
4361 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4362 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4365 LEAVE_GL();
4367 return WINED3D_OK;
4369 #undef copy_and_next
4371 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4372 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4373 DWORD DestFVF)
4375 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4376 struct wined3d_stream_info stream_info;
4377 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4378 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4380 if(pVertexDecl) {
4381 ERR("Output vertex declaration not implemented yet\n");
4384 /* Need any context to write to the vbo. */
4385 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
4387 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4388 * control the streamIsUP flag, thus restore it afterwards.
4390 This->stateBlock->streamIsUP = FALSE;
4391 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4392 This->stateBlock->streamIsUP = streamWasUP;
4394 if(vbo || SrcStartIndex) {
4395 unsigned int i;
4396 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4397 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4399 * Also get the start index in, but only loop over all elements if there's something to add at all.
4401 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4403 struct wined3d_stream_info_element *e;
4405 if (!(stream_info.use_map & (1 << i))) continue;
4407 e = &stream_info.elements[i];
4408 if (e->buffer_object)
4410 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
4411 e->buffer_object = 0;
4412 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
4413 ENTER_GL();
4414 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4415 vb->buffer_object = 0;
4416 LEAVE_GL();
4418 if (e->data) e->data += e->stride * SrcStartIndex;
4422 return process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4423 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4426 /*****
4427 * Get / Set Texture Stage States
4428 * TODO: Verify against dx9 definitions
4429 *****/
4430 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4431 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4432 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4434 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4436 if (Stage >= MAX_TEXTURES) {
4437 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4438 return WINED3D_OK;
4441 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4442 This->updateStateBlock->textureState[Stage][Type] = Value;
4444 if (This->isRecordingState) {
4445 TRACE("Recording... not performing anything\n");
4446 return WINED3D_OK;
4449 /* Checked after the assignments to allow proper stateblock recording */
4450 if(oldValue == Value) {
4451 TRACE("App is setting the old value over, nothing to do\n");
4452 return WINED3D_OK;
4455 if(Stage > This->stateBlock->lowest_disabled_stage &&
4456 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4457 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4458 * Changes in other states are important on disabled stages too
4460 return WINED3D_OK;
4463 if(Type == WINED3DTSS_COLOROP) {
4464 unsigned int i;
4466 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4467 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4468 * they have to be disabled
4470 * The current stage is dirtified below.
4472 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4473 TRACE("Additionally dirtifying stage %u\n", i);
4474 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4476 This->stateBlock->lowest_disabled_stage = Stage;
4477 TRACE("New lowest disabled: %u\n", Stage);
4478 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4479 /* Previously disabled stage enabled. Stages above it may need enabling
4480 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4481 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4483 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4486 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4487 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4488 break;
4490 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4491 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4493 This->stateBlock->lowest_disabled_stage = i;
4494 TRACE("New lowest disabled: %u\n", i);
4498 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4500 return WINED3D_OK;
4503 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4504 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4505 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4506 *pValue = This->updateStateBlock->textureState[Stage][Type];
4507 return WINED3D_OK;
4510 /*****
4511 * Get / Set Texture
4512 *****/
4513 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4514 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4515 IWineD3DBaseTexture *oldTexture;
4517 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4519 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4520 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4523 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4524 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4525 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4528 oldTexture = This->updateStateBlock->textures[Stage];
4530 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4531 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
4533 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4534 return WINED3DERR_INVALIDCALL;
4537 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4538 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4540 This->updateStateBlock->changed.textures |= 1 << Stage;
4541 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4542 This->updateStateBlock->textures[Stage] = pTexture;
4544 /* Handle recording of state blocks */
4545 if (This->isRecordingState) {
4546 TRACE("Recording... not performing anything\n");
4547 return WINED3D_OK;
4550 if(oldTexture == pTexture) {
4551 TRACE("App is setting the same texture again, nothing to do\n");
4552 return WINED3D_OK;
4555 /** NOTE: MSDN says that setTexture increases the reference count,
4556 * and that the application must set the texture back to null (or have a leaky application),
4557 * This means we should pass the refcount up to the parent
4558 *******************************/
4559 if (NULL != This->updateStateBlock->textures[Stage]) {
4560 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4561 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4562 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4564 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4566 if (!oldTexture || dimensions != IWineD3DBaseTexture_GetTextureDimensions(oldTexture))
4568 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4571 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4572 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4573 * so the COLOROP and ALPHAOP have to be dirtified.
4575 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4576 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4578 if(bindCount == 1) {
4579 new->baseTexture.sampler = Stage;
4581 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4585 if (NULL != oldTexture) {
4586 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4587 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4589 IWineD3DBaseTexture_Release(oldTexture);
4590 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4591 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4592 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4595 if(bindCount && old->baseTexture.sampler == Stage) {
4596 int i;
4597 /* Have to do a search for the other sampler(s) where the texture is bound to
4598 * Shouldn't happen as long as apps bind a texture only to one stage
4600 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4601 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4602 if(This->updateStateBlock->textures[i] == oldTexture) {
4603 old->baseTexture.sampler = i;
4604 break;
4610 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4612 return WINED3D_OK;
4615 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4616 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4618 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4620 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4621 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4624 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4625 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4626 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4629 *ppTexture=This->stateBlock->textures[Stage];
4630 if (*ppTexture)
4631 IWineD3DBaseTexture_AddRef(*ppTexture);
4633 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4635 return WINED3D_OK;
4638 /*****
4639 * Get Back Buffer
4640 *****/
4641 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4642 IWineD3DSurface **ppBackBuffer) {
4643 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4644 IWineD3DSwapChain *swapChain;
4645 HRESULT hr;
4647 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4649 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4650 if (hr == WINED3D_OK) {
4651 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4652 IWineD3DSwapChain_Release(swapChain);
4653 } else {
4654 *ppBackBuffer = NULL;
4656 return hr;
4659 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4660 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4661 WARN("(%p) : stub, calling idirect3d for now\n", This);
4662 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4665 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4666 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4667 IWineD3DSwapChain *swapChain;
4668 HRESULT hr;
4670 if(iSwapChain > 0) {
4671 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4672 if (hr == WINED3D_OK) {
4673 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4674 IWineD3DSwapChain_Release(swapChain);
4675 } else {
4676 FIXME("(%p) Error getting display mode\n", This);
4678 } else {
4679 /* Don't read the real display mode,
4680 but return the stored mode instead. X11 can't change the color
4681 depth, and some apps are pretty angry if they SetDisplayMode from
4682 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4684 Also don't relay to the swapchain because with ddraw it's possible
4685 that there isn't a swapchain at all */
4686 pMode->Width = This->ddraw_width;
4687 pMode->Height = This->ddraw_height;
4688 pMode->Format = This->ddraw_format;
4689 pMode->RefreshRate = 0;
4690 hr = WINED3D_OK;
4693 return hr;
4696 /*****
4697 * Stateblock related functions
4698 *****/
4700 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4701 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4702 IWineD3DStateBlock *stateblock;
4703 HRESULT hr;
4705 TRACE("(%p)\n", This);
4707 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4709 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4710 if (FAILED(hr)) return hr;
4712 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4713 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4714 This->isRecordingState = TRUE;
4716 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4718 return WINED3D_OK;
4721 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4722 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4723 unsigned int i, j;
4724 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4726 if (!This->isRecordingState) {
4727 WARN("(%p) not recording! returning error\n", This);
4728 *ppStateBlock = NULL;
4729 return WINED3DERR_INVALIDCALL;
4732 for (i = 0; i <= WINEHIGHEST_RENDER_STATE >> 5; ++i)
4734 DWORD map = object->changed.renderState[i];
4735 for (j = 0; map; map >>= 1, ++j)
4737 if (!(map & 1)) continue;
4739 object->contained_render_states[object->num_contained_render_states++] = (i << 5) | j;
4743 for (i = 0; i <= HIGHEST_TRANSFORMSTATE >> 5; ++i)
4745 DWORD map = object->changed.transform[i];
4746 for (j = 0; map; map >>= 1, ++j)
4748 if (!(map & 1)) continue;
4750 object->contained_transform_states[object->num_contained_transform_states++] = (i << 5) | j;
4753 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4754 if(object->changed.vertexShaderConstantsF[i]) {
4755 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4756 object->num_contained_vs_consts_f++;
4759 for(i = 0; i < MAX_CONST_I; i++) {
4760 if (object->changed.vertexShaderConstantsI & (1 << i))
4762 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4763 object->num_contained_vs_consts_i++;
4766 for(i = 0; i < MAX_CONST_B; i++) {
4767 if (object->changed.vertexShaderConstantsB & (1 << i))
4769 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4770 object->num_contained_vs_consts_b++;
4773 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
4775 if (object->changed.pixelShaderConstantsF[i])
4777 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
4778 ++object->num_contained_ps_consts_f;
4781 for(i = 0; i < MAX_CONST_I; i++) {
4782 if (object->changed.pixelShaderConstantsI & (1 << i))
4784 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4785 object->num_contained_ps_consts_i++;
4788 for(i = 0; i < MAX_CONST_B; i++) {
4789 if (object->changed.pixelShaderConstantsB & (1 << i))
4791 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4792 object->num_contained_ps_consts_b++;
4795 for(i = 0; i < MAX_TEXTURES; i++) {
4796 DWORD map = object->changed.textureState[i];
4798 for(j = 0; map; map >>= 1, ++j)
4800 if (!(map & 1)) continue;
4802 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4803 object->contained_tss_states[object->num_contained_tss_states].state = j;
4804 ++object->num_contained_tss_states;
4807 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4808 DWORD map = object->changed.samplerState[i];
4810 for (j = 0; map; map >>= 1, ++j)
4812 if (!(map & 1)) continue;
4814 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4815 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4816 ++object->num_contained_sampler_states;
4820 *ppStateBlock = (IWineD3DStateBlock*) object;
4821 This->isRecordingState = FALSE;
4822 This->updateStateBlock = This->stateBlock;
4823 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4824 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4825 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4826 return WINED3D_OK;
4829 /*****
4830 * Scene related functions
4831 *****/
4832 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4833 /* At the moment we have no need for any functionality at the beginning
4834 of a scene */
4835 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4836 TRACE("(%p)\n", This);
4838 if(This->inScene) {
4839 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4840 return WINED3DERR_INVALIDCALL;
4842 This->inScene = TRUE;
4843 return WINED3D_OK;
4846 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4847 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4848 TRACE("(%p)\n", This);
4850 if(!This->inScene) {
4851 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4852 return WINED3DERR_INVALIDCALL;
4855 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
4856 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4857 wglFlush();
4858 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4859 * fails
4862 This->inScene = FALSE;
4863 return WINED3D_OK;
4866 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4867 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4868 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4869 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4870 IWineD3DSwapChain *swapChain = NULL;
4871 int i;
4872 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4874 TRACE("(%p) Presenting the frame\n", This);
4876 for(i = 0 ; i < swapchains ; i ++) {
4878 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4879 TRACE("presentinng chain %d, %p\n", i, swapChain);
4880 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4881 IWineD3DSwapChain_Release(swapChain);
4884 return WINED3D_OK;
4887 /* Not called from the VTable (internal subroutine) */
4888 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4889 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4890 float Z, DWORD Stencil) {
4891 GLbitfield glMask = 0;
4892 unsigned int i;
4893 WINED3DRECT curRect;
4894 RECT vp_rect;
4895 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4896 UINT drawable_width, drawable_height;
4897 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4898 IWineD3DSwapChainImpl *swapchain = NULL;
4899 struct wined3d_context *context;
4901 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4902 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4903 * for the cleared parts, and the untouched parts.
4905 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4906 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4907 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4908 * checking all this if the dest surface is in the drawable anyway.
4910 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4911 while(1) {
4912 if(vp->X != 0 || vp->Y != 0 ||
4913 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4914 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4915 break;
4917 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4918 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4919 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4920 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4921 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4922 break;
4924 if(Count > 0 && pRects && (
4925 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4926 pRects[0].x2 < target->currentDesc.Width ||
4927 pRects[0].y2 < target->currentDesc.Height)) {
4928 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4929 break;
4931 break;
4935 context = ActivateContext(This, (IWineD3DSurface *)target, CTXUSAGE_CLEAR);
4937 target->get_drawable_size(context, &drawable_width, &drawable_height);
4939 ENTER_GL();
4941 /* Only set the values up once, as they are not changing */
4942 if (Flags & WINED3DCLEAR_STENCIL) {
4943 glClearStencil(Stencil);
4944 checkGLcall("glClearStencil");
4945 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4946 glStencilMask(0xFFFFFFFF);
4949 if (Flags & WINED3DCLEAR_ZBUFFER) {
4950 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4951 glDepthMask(GL_TRUE);
4952 glClearDepth(Z);
4953 checkGLcall("glClearDepth");
4954 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4955 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4957 if (vp->X != 0 || vp->Y != 0 ||
4958 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4959 surface_load_ds_location(This->stencilBufferTarget, context, location);
4961 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4962 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4963 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4964 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4965 surface_load_ds_location(This->stencilBufferTarget, context, location);
4967 else if (Count > 0 && pRects && (
4968 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4969 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4970 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4971 surface_load_ds_location(This->stencilBufferTarget, context, location);
4975 if (Flags & WINED3DCLEAR_TARGET) {
4976 TRACE("Clearing screen with glClear to color %x\n", Color);
4977 glClearColor(D3DCOLOR_R(Color),
4978 D3DCOLOR_G(Color),
4979 D3DCOLOR_B(Color),
4980 D3DCOLOR_A(Color));
4981 checkGLcall("glClearColor");
4983 /* Clear ALL colors! */
4984 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4985 glMask = glMask | GL_COLOR_BUFFER_BIT;
4988 vp_rect.left = vp->X;
4989 vp_rect.top = vp->Y;
4990 vp_rect.right = vp->X + vp->Width;
4991 vp_rect.bottom = vp->Y + vp->Height;
4992 if (!(Count > 0 && pRects)) {
4993 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4994 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4996 if (context->render_offscreen)
4998 glScissor(vp_rect.left, vp_rect.top,
4999 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5000 } else {
5001 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5002 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5004 checkGLcall("glScissor");
5005 glClear(glMask);
5006 checkGLcall("glClear");
5007 } else {
5008 /* Now process each rect in turn */
5009 for (i = 0; i < Count; i++) {
5010 /* Note gl uses lower left, width/height */
5011 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5012 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5013 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5015 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5016 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5017 curRect.x1, (target->currentDesc.Height - curRect.y2),
5018 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5020 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5021 * The rectangle is not cleared, no error is returned, but further rectanlges are
5022 * still cleared if they are valid
5024 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5025 TRACE("Rectangle with negative dimensions, ignoring\n");
5026 continue;
5029 if (context->render_offscreen)
5031 glScissor(curRect.x1, curRect.y1,
5032 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5033 } else {
5034 glScissor(curRect.x1, drawable_height - curRect.y2,
5035 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5037 checkGLcall("glScissor");
5039 glClear(glMask);
5040 checkGLcall("glClear");
5044 /* Restore the old values (why..?) */
5045 if (Flags & WINED3DCLEAR_STENCIL) {
5046 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5048 if (Flags & WINED3DCLEAR_TARGET) {
5049 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5050 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5051 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5052 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5053 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5055 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5056 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5058 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
5060 if (Flags & WINED3DCLEAR_ZBUFFER) {
5061 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5062 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5063 surface_modify_ds_location(This->stencilBufferTarget, location);
5066 LEAVE_GL();
5068 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5069 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5070 wglFlush();
5072 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5075 return WINED3D_OK;
5078 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5079 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5080 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5081 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5083 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5084 Count, pRects, Flags, Color, Z, Stencil);
5086 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5087 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5088 /* TODO: What about depth stencil buffers without stencil bits? */
5089 return WINED3DERR_INVALIDCALL;
5092 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5095 /*****
5096 * Drawing functions
5097 *****/
5099 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
5100 WINED3DPRIMITIVETYPE primitive_type)
5102 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5104 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
5106 This->updateStateBlock->changed.primitive_type = TRUE;
5107 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
5110 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
5111 WINED3DPRIMITIVETYPE *primitive_type)
5113 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5115 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
5117 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
5119 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
5122 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
5124 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5126 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
5128 if(!This->stateBlock->vertexDecl) {
5129 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5130 return WINED3DERR_INVALIDCALL;
5133 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5134 if(This->stateBlock->streamIsUP) {
5135 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5136 This->stateBlock->streamIsUP = FALSE;
5139 if(This->stateBlock->loadBaseVertexIndex != 0) {
5140 This->stateBlock->loadBaseVertexIndex = 0;
5141 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5143 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5144 drawPrimitive(iface, vertex_count, 0/* NumVertices */, StartVertex /* start_idx */,
5145 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5146 return WINED3D_OK;
5149 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5150 UINT minIndex, UINT NumVertices, UINT startIndex, UINT index_count)
5152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5153 UINT idxStride = 2;
5154 IWineD3DBuffer *pIB;
5155 GLuint vbo;
5157 pIB = This->stateBlock->pIndexData;
5158 if (!pIB) {
5159 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5160 * without an index buffer set. (The first time at least...)
5161 * D3D8 simply dies, but I doubt it can do much harm to return
5162 * D3DERR_INVALIDCALL there as well. */
5163 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5164 return WINED3DERR_INVALIDCALL;
5167 if(!This->stateBlock->vertexDecl) {
5168 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5169 return WINED3DERR_INVALIDCALL;
5172 if(This->stateBlock->streamIsUP) {
5173 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5174 This->stateBlock->streamIsUP = FALSE;
5176 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
5178 TRACE("(%p) : min %u, vertex count %u, startIdx %u, index count %u\n",
5179 This, minIndex, NumVertices, startIndex, index_count);
5181 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
5182 idxStride = 2;
5183 } else {
5184 idxStride = 4;
5187 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5188 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5189 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5192 drawPrimitive(iface, index_count, NumVertices, startIndex, idxStride,
5193 vbo ? NULL : ((struct wined3d_buffer *) pIB)->resource.allocatedMemory, minIndex);
5195 return WINED3D_OK;
5198 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
5199 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5201 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5202 IWineD3DBuffer *vb;
5204 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
5205 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
5207 if(!This->stateBlock->vertexDecl) {
5208 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5209 return WINED3DERR_INVALIDCALL;
5212 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5213 vb = This->stateBlock->streamSource[0];
5214 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5215 if (vb) IWineD3DBuffer_Release(vb);
5216 This->stateBlock->streamOffset[0] = 0;
5217 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5218 This->stateBlock->streamIsUP = TRUE;
5219 This->stateBlock->loadBaseVertexIndex = 0;
5221 /* TODO: Only mark dirty if drawing from a different UP address */
5222 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5224 drawPrimitive(iface, vertex_count, 0 /* NumVertices */, 0 /* start_idx */,
5225 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5227 /* MSDN specifies stream zero settings must be set to NULL */
5228 This->stateBlock->streamStride[0] = 0;
5229 This->stateBlock->streamSource[0] = NULL;
5231 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5232 * the new stream sources or use UP drawing again
5234 return WINED3D_OK;
5237 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, UINT MinVertexIndex,
5238 UINT NumVertices, UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
5239 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5241 int idxStride;
5242 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5243 IWineD3DBuffer *vb;
5244 IWineD3DBuffer *ib;
5246 TRACE("(%p) : MinVtxIdx %u, NumVIdx %u, index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u\n",
5247 This, MinVertexIndex, NumVertices, index_count, pIndexData,
5248 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5250 if(!This->stateBlock->vertexDecl) {
5251 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5252 return WINED3DERR_INVALIDCALL;
5255 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
5256 idxStride = 2;
5257 } else {
5258 idxStride = 4;
5261 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5262 vb = This->stateBlock->streamSource[0];
5263 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5264 if (vb) IWineD3DBuffer_Release(vb);
5265 This->stateBlock->streamIsUP = TRUE;
5266 This->stateBlock->streamOffset[0] = 0;
5267 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5269 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5270 This->stateBlock->baseVertexIndex = 0;
5271 This->stateBlock->loadBaseVertexIndex = 0;
5272 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5273 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5274 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5276 drawPrimitive(iface, index_count, NumVertices, 0 /* start_idx */,
5277 idxStride, pIndexData, MinVertexIndex);
5279 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5280 This->stateBlock->streamSource[0] = NULL;
5281 This->stateBlock->streamStride[0] = 0;
5282 ib = This->stateBlock->pIndexData;
5283 if(ib) {
5284 IWineD3DBuffer_Release(ib);
5285 This->stateBlock->pIndexData = NULL;
5287 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5288 * SetStreamSource to specify a vertex buffer
5291 return WINED3D_OK;
5294 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5295 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
5297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5299 /* Mark the state dirty until we have nicer tracking
5300 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5301 * that value.
5303 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5304 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5305 This->stateBlock->baseVertexIndex = 0;
5306 This->up_strided = DrawPrimStrideData;
5307 drawPrimitive(iface, vertex_count, 0, 0, 0, NULL, 0);
5308 This->up_strided = NULL;
5309 return WINED3D_OK;
5312 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5313 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
5314 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
5316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5317 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5319 /* Mark the state dirty until we have nicer tracking
5320 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5321 * that value.
5323 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5324 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5325 This->stateBlock->streamIsUP = TRUE;
5326 This->stateBlock->baseVertexIndex = 0;
5327 This->up_strided = DrawPrimStrideData;
5328 drawPrimitive(iface, vertex_count, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData, 0 /* minindex */);
5329 This->up_strided = NULL;
5330 return WINED3D_OK;
5333 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5334 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5335 * not callable by the app directly no parameter validation checks are needed here.
5337 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5338 WINED3DLOCKED_BOX src;
5339 WINED3DLOCKED_BOX dst;
5340 HRESULT hr;
5341 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5343 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5344 * dirtification to improve loading performance.
5346 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5347 if(FAILED(hr)) return hr;
5348 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5349 if(FAILED(hr)) {
5350 IWineD3DVolume_UnlockBox(pSourceVolume);
5351 return hr;
5354 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5356 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5357 if(FAILED(hr)) {
5358 IWineD3DVolume_UnlockBox(pSourceVolume);
5359 } else {
5360 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5362 return hr;
5365 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5366 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5367 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5368 HRESULT hr = WINED3D_OK;
5369 WINED3DRESOURCETYPE sourceType;
5370 WINED3DRESOURCETYPE destinationType;
5371 int i ,levels;
5373 /* TODO: think about moving the code into IWineD3DBaseTexture */
5375 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5377 /* verify that the source and destination textures aren't NULL */
5378 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5379 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5380 This, pSourceTexture, pDestinationTexture);
5381 hr = WINED3DERR_INVALIDCALL;
5384 if (pSourceTexture == pDestinationTexture) {
5385 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5386 This, pSourceTexture, pDestinationTexture);
5387 hr = WINED3DERR_INVALIDCALL;
5389 /* Verify that the source and destination textures are the same type */
5390 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5391 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5393 if (sourceType != destinationType) {
5394 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5395 This);
5396 hr = WINED3DERR_INVALIDCALL;
5399 /* check that both textures have the identical numbers of levels */
5400 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5401 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5402 hr = WINED3DERR_INVALIDCALL;
5405 if (WINED3D_OK == hr) {
5406 IWineD3DBaseTextureImpl *pDestImpl = (IWineD3DBaseTextureImpl *) pDestinationTexture;
5408 /* Make sure that the destination texture is loaded */
5409 pDestImpl->baseTexture.internal_preload(pDestinationTexture, SRGB_RGB);
5411 /* Update every surface level of the texture */
5412 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5414 switch (sourceType) {
5415 case WINED3DRTYPE_TEXTURE:
5417 IWineD3DSurface *srcSurface;
5418 IWineD3DSurface *destSurface;
5420 for (i = 0 ; i < levels ; ++i) {
5421 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5422 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5423 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5424 IWineD3DSurface_Release(srcSurface);
5425 IWineD3DSurface_Release(destSurface);
5426 if (WINED3D_OK != hr) {
5427 WARN("(%p) : Call to update surface failed\n", This);
5428 return hr;
5432 break;
5433 case WINED3DRTYPE_CUBETEXTURE:
5435 IWineD3DSurface *srcSurface;
5436 IWineD3DSurface *destSurface;
5437 WINED3DCUBEMAP_FACES faceType;
5439 for (i = 0 ; i < levels ; ++i) {
5440 /* Update each cube face */
5441 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5442 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5443 if (WINED3D_OK != hr) {
5444 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5445 } else {
5446 TRACE("Got srcSurface %p\n", srcSurface);
5448 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5449 if (WINED3D_OK != hr) {
5450 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5451 } else {
5452 TRACE("Got desrSurface %p\n", destSurface);
5454 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5455 IWineD3DSurface_Release(srcSurface);
5456 IWineD3DSurface_Release(destSurface);
5457 if (WINED3D_OK != hr) {
5458 WARN("(%p) : Call to update surface failed\n", This);
5459 return hr;
5464 break;
5466 case WINED3DRTYPE_VOLUMETEXTURE:
5468 IWineD3DVolume *srcVolume = NULL;
5469 IWineD3DVolume *destVolume = NULL;
5471 for (i = 0 ; i < levels ; ++i) {
5472 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5473 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5474 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5475 IWineD3DVolume_Release(srcVolume);
5476 IWineD3DVolume_Release(destVolume);
5477 if (WINED3D_OK != hr) {
5478 WARN("(%p) : Call to update volume failed\n", This);
5479 return hr;
5483 break;
5485 default:
5486 FIXME("(%p) : Unsupported source and destination type\n", This);
5487 hr = WINED3DERR_INVALIDCALL;
5491 return hr;
5494 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5495 IWineD3DSwapChain *swapChain;
5496 HRESULT hr;
5497 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5498 if(hr == WINED3D_OK) {
5499 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5500 IWineD3DSwapChain_Release(swapChain);
5502 return hr;
5505 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5506 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5507 IWineD3DBaseTextureImpl *texture;
5508 DWORD i;
5510 TRACE("(%p) : %p\n", This, pNumPasses);
5512 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5513 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5514 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5515 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5517 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5518 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5519 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5522 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5523 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5525 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5526 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5527 return E_FAIL;
5529 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5530 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5531 return E_FAIL;
5533 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5534 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5535 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5536 return E_FAIL;
5540 /* return a sensible default */
5541 *pNumPasses = 1;
5543 TRACE("returning D3D_OK\n");
5544 return WINED3D_OK;
5547 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5549 int i;
5551 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5552 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5553 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8
5554 || texture->resource.format_desc->format == WINED3DFMT_A8P8))
5556 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5561 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5562 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5563 int j;
5564 UINT NewSize;
5565 PALETTEENTRY **palettes;
5567 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5569 if (PaletteNumber >= MAX_PALETTES) {
5570 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5571 return WINED3DERR_INVALIDCALL;
5574 if (PaletteNumber >= This->NumberOfPalettes) {
5575 NewSize = This->NumberOfPalettes;
5576 do {
5577 NewSize *= 2;
5578 } while(PaletteNumber >= NewSize);
5579 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5580 if (!palettes) {
5581 ERR("Out of memory!\n");
5582 return E_OUTOFMEMORY;
5584 This->palettes = palettes;
5585 This->NumberOfPalettes = NewSize;
5588 if (!This->palettes[PaletteNumber]) {
5589 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5590 if (!This->palettes[PaletteNumber]) {
5591 ERR("Out of memory!\n");
5592 return E_OUTOFMEMORY;
5596 for (j = 0; j < 256; ++j) {
5597 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5598 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5599 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5600 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5602 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5603 TRACE("(%p) : returning\n", This);
5604 return WINED3D_OK;
5607 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5608 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5609 int j;
5610 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5611 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5612 /* What happens in such situation isn't documented; Native seems to silently abort
5613 on such conditions. Return Invalid Call. */
5614 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5615 return WINED3DERR_INVALIDCALL;
5617 for (j = 0; j < 256; ++j) {
5618 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5619 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5620 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5621 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5623 TRACE("(%p) : returning\n", This);
5624 return WINED3D_OK;
5627 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5628 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5629 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5630 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5631 (tested with reference rasterizer). Return Invalid Call. */
5632 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5633 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5634 return WINED3DERR_INVALIDCALL;
5636 /*TODO: stateblocks */
5637 if (This->currentPalette != PaletteNumber) {
5638 This->currentPalette = PaletteNumber;
5639 dirtify_p8_texture_samplers(This);
5641 TRACE("(%p) : returning\n", This);
5642 return WINED3D_OK;
5645 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5646 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5647 if (PaletteNumber == NULL) {
5648 WARN("(%p) : returning Invalid Call\n", This);
5649 return WINED3DERR_INVALIDCALL;
5651 /*TODO: stateblocks */
5652 *PaletteNumber = This->currentPalette;
5653 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5654 return WINED3D_OK;
5657 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5658 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5659 static BOOL warned;
5660 if (!warned)
5662 FIXME("(%p) : stub\n", This);
5663 warned = TRUE;
5666 This->softwareVertexProcessing = bSoftware;
5667 return WINED3D_OK;
5671 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5672 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5673 static BOOL warned;
5674 if (!warned)
5676 FIXME("(%p) : stub\n", This);
5677 warned = TRUE;
5679 return This->softwareVertexProcessing;
5683 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5684 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5685 IWineD3DSwapChain *swapChain;
5686 HRESULT hr;
5688 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5690 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5691 if(hr == WINED3D_OK){
5692 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5693 IWineD3DSwapChain_Release(swapChain);
5694 }else{
5695 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5697 return hr;
5701 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5702 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5703 static BOOL warned;
5704 if(nSegments != 0.0f) {
5705 if (!warned)
5707 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5708 warned = TRUE;
5711 return WINED3D_OK;
5714 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5715 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5716 static BOOL warned;
5717 if (!warned)
5719 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5720 warned = TRUE;
5722 return 0.0f;
5725 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5726 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5727 /** TODO: remove casts to IWineD3DSurfaceImpl
5728 * NOTE: move code to surface to accomplish this
5729 ****************************************/
5730 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5731 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)pDestinationSurface;
5732 int srcWidth, srcHeight;
5733 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5734 WINED3DFORMAT destFormat, srcFormat;
5735 UINT destSize;
5736 int srcLeft, destLeft, destTop;
5737 WINED3DPOOL srcPool, destPool;
5738 int offset = 0;
5739 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5740 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
5741 GLenum dummy;
5742 DWORD sampler;
5743 int bpp;
5744 CONVERT_TYPES convert = NO_CONVERSION;
5746 WINED3DSURFACE_DESC winedesc;
5748 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5750 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5751 srcSurfaceWidth = winedesc.width;
5752 srcSurfaceHeight = winedesc.height;
5753 srcPool = winedesc.pool;
5754 srcFormat = winedesc.format;
5756 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5757 destSurfaceWidth = winedesc.width;
5758 destSurfaceHeight = winedesc.height;
5759 destPool = winedesc.pool;
5760 destFormat = winedesc.format;
5761 destSize = winedesc.size;
5763 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5764 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5765 return WINED3DERR_INVALIDCALL;
5768 /* This call loads the opengl surface directly, instead of copying the surface to the
5769 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5770 * copy in sysmem and use regular surface loading.
5772 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5773 if(convert != NO_CONVERSION) {
5774 return IWineD3DSurface_BltFast(pDestinationSurface,
5775 pDestPoint ? pDestPoint->x : 0,
5776 pDestPoint ? pDestPoint->y : 0,
5777 pSourceSurface, pSourceRect, 0);
5780 if (destFormat == WINED3DFMT_UNKNOWN) {
5781 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5782 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5784 /* Get the update surface description */
5785 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5788 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
5790 ENTER_GL();
5791 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5792 checkGLcall("glActiveTextureARB");
5793 LEAVE_GL();
5795 /* Make sure the surface is loaded and up to date */
5796 surface_internal_preload(pDestinationSurface, SRGB_RGB);
5797 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5799 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
5800 dst_format_desc = dst_impl->resource.format_desc;
5802 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5803 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5804 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5805 srcLeft = pSourceRect ? pSourceRect->left : 0;
5806 destLeft = pDestPoint ? pDestPoint->x : 0;
5807 destTop = pDestPoint ? pDestPoint->y : 0;
5810 /* This function doesn't support compressed textures
5811 the pitch is just bytesPerPixel * width */
5812 if(srcWidth != srcSurfaceWidth || srcLeft ){
5813 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
5814 offset += srcLeft * src_format_desc->byte_count;
5815 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5817 /* TODO DXT formats */
5819 if(pSourceRect != NULL && pSourceRect->top != 0){
5820 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
5822 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5823 This, dst_impl->texture_level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
5824 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5826 /* Sanity check */
5827 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5829 /* need to lock the surface to get the data */
5830 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5833 ENTER_GL();
5835 /* TODO: Cube and volume support */
5836 if(rowoffset != 0){
5837 /* not a whole row so we have to do it a line at a time */
5838 int j;
5840 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5841 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5843 for (j = destTop; j < (srcHeight + destTop); ++j)
5845 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, j,
5846 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
5847 data += rowoffset;
5850 } else { /* Full width, so just write out the whole texture */
5851 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5853 if (dst_format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
5855 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth)
5857 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across. */
5858 FIXME("Updating part of a compressed texture is not supported.\n");
5860 if (destFormat != srcFormat)
5862 FIXME("Updating mixed format compressed textures is not supported.\n");
5864 else
5866 GL_EXTCALL(glCompressedTexImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5867 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
5870 else
5872 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, destTop,
5873 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
5876 checkGLcall("glTexSubImage2D");
5878 LEAVE_GL();
5880 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5881 sampler = This->rev_tex_unit_map[0];
5882 if (sampler != WINED3D_UNMAPPED_STAGE)
5884 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5887 return WINED3D_OK;
5890 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5891 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5892 struct WineD3DRectPatch *patch;
5893 GLenum old_primitive_type;
5894 unsigned int i;
5895 struct list *e;
5896 BOOL found;
5897 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5899 if(!(Handle || pRectPatchInfo)) {
5900 /* TODO: Write a test for the return value, thus the FIXME */
5901 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5902 return WINED3DERR_INVALIDCALL;
5905 if(Handle) {
5906 i = PATCHMAP_HASHFUNC(Handle);
5907 found = FALSE;
5908 LIST_FOR_EACH(e, &This->patches[i]) {
5909 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5910 if(patch->Handle == Handle) {
5911 found = TRUE;
5912 break;
5916 if(!found) {
5917 TRACE("Patch does not exist. Creating a new one\n");
5918 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5919 patch->Handle = Handle;
5920 list_add_head(&This->patches[i], &patch->entry);
5921 } else {
5922 TRACE("Found existing patch %p\n", patch);
5924 } else {
5925 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5926 * attributes we have to tesselate, read back, and draw. This needs a patch
5927 * management structure instance. Create one.
5929 * A possible improvement is to check if a vertex shader is used, and if not directly
5930 * draw the patch.
5932 FIXME("Drawing an uncached patch. This is slow\n");
5933 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5936 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5937 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5938 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5939 HRESULT hr;
5940 TRACE("Tesselation density or patch info changed, retesselating\n");
5942 if(pRectPatchInfo) {
5943 patch->RectPatchInfo = *pRectPatchInfo;
5945 patch->numSegs[0] = pNumSegs[0];
5946 patch->numSegs[1] = pNumSegs[1];
5947 patch->numSegs[2] = pNumSegs[2];
5948 patch->numSegs[3] = pNumSegs[3];
5950 hr = tesselate_rectpatch(This, patch);
5951 if(FAILED(hr)) {
5952 WARN("Patch tesselation failed\n");
5954 /* Do not release the handle to store the params of the patch */
5955 if(!Handle) {
5956 HeapFree(GetProcessHeap(), 0, patch);
5958 return hr;
5962 This->currentPatch = patch;
5963 old_primitive_type = This->stateBlock->gl_primitive_type;
5964 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5965 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5966 This->stateBlock->gl_primitive_type = old_primitive_type;
5967 This->currentPatch = NULL;
5969 /* Destroy uncached patches */
5970 if(!Handle) {
5971 HeapFree(GetProcessHeap(), 0, patch->mem);
5972 HeapFree(GetProcessHeap(), 0, patch);
5974 return WINED3D_OK;
5977 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5978 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5979 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5980 FIXME("(%p) : Stub\n", This);
5981 return WINED3D_OK;
5984 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5985 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5986 int i;
5987 struct WineD3DRectPatch *patch;
5988 struct list *e;
5989 TRACE("(%p) Handle(%d)\n", This, Handle);
5991 i = PATCHMAP_HASHFUNC(Handle);
5992 LIST_FOR_EACH(e, &This->patches[i]) {
5993 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5994 if(patch->Handle == Handle) {
5995 TRACE("Deleting patch %p\n", patch);
5996 list_remove(&patch->entry);
5997 HeapFree(GetProcessHeap(), 0, patch->mem);
5998 HeapFree(GetProcessHeap(), 0, patch);
5999 return WINED3D_OK;
6003 /* TODO: Write a test for the return value */
6004 FIXME("Attempt to destroy nonexistent patch\n");
6005 return WINED3DERR_INVALIDCALL;
6008 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6009 HRESULT hr;
6010 IWineD3DSwapChain *swapchain;
6012 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6013 if (SUCCEEDED(hr)) {
6014 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6015 return swapchain;
6018 return NULL;
6021 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
6022 const WINED3DRECT *rect, const float color[4])
6024 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6025 struct wined3d_context *context;
6026 IWineD3DSwapChain *swapchain;
6028 swapchain = get_swapchain(surface);
6029 if (swapchain) {
6030 GLenum buffer;
6032 TRACE("Surface %p is onscreen\n", surface);
6034 context = ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6035 ENTER_GL();
6036 context_bind_fbo(context, GL_FRAMEBUFFER_EXT, NULL);
6037 buffer = surface_get_gl_buffer(surface, swapchain);
6038 glDrawBuffer(buffer);
6039 checkGLcall("glDrawBuffer()");
6040 } else {
6041 TRACE("Surface %p is offscreen\n", surface);
6043 context = ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6044 ENTER_GL();
6045 context_bind_fbo(context, GL_FRAMEBUFFER_EXT, &context->dst_fbo);
6046 context_attach_surface_fbo(context, GL_FRAMEBUFFER_EXT, 0, surface);
6047 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER_EXT, NULL, FALSE);
6050 if (rect) {
6051 glEnable(GL_SCISSOR_TEST);
6052 if(!swapchain) {
6053 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6054 } else {
6055 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6056 rect->x2 - rect->x1, rect->y2 - rect->y1);
6058 checkGLcall("glScissor");
6059 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6060 } else {
6061 glDisable(GL_SCISSOR_TEST);
6063 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6065 glDisable(GL_BLEND);
6066 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6068 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6069 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6071 glClearColor(color[0], color[1], color[2], color[3]);
6072 glClear(GL_COLOR_BUFFER_BIT);
6073 checkGLcall("glClear");
6075 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6076 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6077 glDrawBuffer(GL_BACK);
6078 checkGLcall("glDrawBuffer()");
6081 LEAVE_GL();
6084 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6085 unsigned int r, g, b, a;
6086 DWORD ret;
6088 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6089 destfmt == WINED3DFMT_R8G8B8)
6090 return color;
6092 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6094 a = (color & 0xff000000) >> 24;
6095 r = (color & 0x00ff0000) >> 16;
6096 g = (color & 0x0000ff00) >> 8;
6097 b = (color & 0x000000ff) >> 0;
6099 switch(destfmt)
6101 case WINED3DFMT_R5G6B5:
6102 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6103 r = (r * 32) / 256;
6104 g = (g * 64) / 256;
6105 b = (b * 32) / 256;
6106 ret = r << 11;
6107 ret |= g << 5;
6108 ret |= b;
6109 TRACE("Returning %08x\n", ret);
6110 return ret;
6112 case WINED3DFMT_X1R5G5B5:
6113 case WINED3DFMT_A1R5G5B5:
6114 a = (a * 2) / 256;
6115 r = (r * 32) / 256;
6116 g = (g * 32) / 256;
6117 b = (b * 32) / 256;
6118 ret = a << 15;
6119 ret |= r << 10;
6120 ret |= g << 5;
6121 ret |= b << 0;
6122 TRACE("Returning %08x\n", ret);
6123 return ret;
6125 case WINED3DFMT_A8_UNORM:
6126 TRACE("Returning %08x\n", a);
6127 return a;
6129 case WINED3DFMT_X4R4G4B4:
6130 case WINED3DFMT_A4R4G4B4:
6131 a = (a * 16) / 256;
6132 r = (r * 16) / 256;
6133 g = (g * 16) / 256;
6134 b = (b * 16) / 256;
6135 ret = a << 12;
6136 ret |= r << 8;
6137 ret |= g << 4;
6138 ret |= b << 0;
6139 TRACE("Returning %08x\n", ret);
6140 return ret;
6142 case WINED3DFMT_R3G3B2:
6143 r = (r * 8) / 256;
6144 g = (g * 8) / 256;
6145 b = (b * 4) / 256;
6146 ret = r << 5;
6147 ret |= g << 2;
6148 ret |= b << 0;
6149 TRACE("Returning %08x\n", ret);
6150 return ret;
6152 case WINED3DFMT_X8B8G8R8:
6153 case WINED3DFMT_R8G8B8A8_UNORM:
6154 ret = a << 24;
6155 ret |= b << 16;
6156 ret |= g << 8;
6157 ret |= r << 0;
6158 TRACE("Returning %08x\n", ret);
6159 return ret;
6161 case WINED3DFMT_A2R10G10B10:
6162 a = (a * 4) / 256;
6163 r = (r * 1024) / 256;
6164 g = (g * 1024) / 256;
6165 b = (b * 1024) / 256;
6166 ret = a << 30;
6167 ret |= r << 20;
6168 ret |= g << 10;
6169 ret |= b << 0;
6170 TRACE("Returning %08x\n", ret);
6171 return ret;
6173 case WINED3DFMT_R10G10B10A2_UNORM:
6174 a = (a * 4) / 256;
6175 r = (r * 1024) / 256;
6176 g = (g * 1024) / 256;
6177 b = (b * 1024) / 256;
6178 ret = a << 30;
6179 ret |= b << 20;
6180 ret |= g << 10;
6181 ret |= r << 0;
6182 TRACE("Returning %08x\n", ret);
6183 return ret;
6185 default:
6186 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6187 return 0;
6191 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6193 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6194 WINEDDBLTFX BltFx;
6195 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6197 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6198 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6199 return WINED3DERR_INVALIDCALL;
6202 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6203 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
6204 color_fill_fbo(iface, pSurface, pRect, c);
6205 return WINED3D_OK;
6206 } else {
6207 /* Just forward this to the DirectDraw blitting engine */
6208 memset(&BltFx, 0, sizeof(BltFx));
6209 BltFx.dwSize = sizeof(BltFx);
6210 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
6211 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6212 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
6216 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
6217 IWineD3DRendertargetView *rendertarget_view, const float color[4])
6219 IWineD3DResource *resource;
6220 IWineD3DSurface *surface;
6221 HRESULT hr;
6223 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
6224 if (FAILED(hr))
6226 ERR("Failed to get resource, hr %#x\n", hr);
6227 return;
6230 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
6232 FIXME("Only supported on surface resources\n");
6233 IWineD3DResource_Release(resource);
6234 return;
6237 surface = (IWineD3DSurface *)resource;
6239 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6241 color_fill_fbo(iface, surface, NULL, color);
6243 else
6245 WINEDDBLTFX BltFx;
6246 WINED3DCOLOR c;
6248 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
6250 c = ((DWORD)(color[2] * 255.0f));
6251 c |= ((DWORD)(color[1] * 255.0f)) << 8;
6252 c |= ((DWORD)(color[0] * 255.0f)) << 16;
6253 c |= ((DWORD)(color[3] * 255.0f)) << 24;
6255 /* Just forward this to the DirectDraw blitting engine */
6256 memset(&BltFx, 0, sizeof(BltFx));
6257 BltFx.dwSize = sizeof(BltFx);
6258 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
6259 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
6260 if (FAILED(hr))
6262 ERR("Blt failed, hr %#x\n", hr);
6266 IWineD3DResource_Release(resource);
6269 /* rendertarget and depth stencil functions */
6270 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6271 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6273 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6274 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6275 return WINED3DERR_INVALIDCALL;
6278 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6279 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6280 /* Note inc ref on returned surface */
6281 if(*ppRenderTarget != NULL)
6282 IWineD3DSurface_AddRef(*ppRenderTarget);
6283 return WINED3D_OK;
6286 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6287 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6288 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6289 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6290 IWineD3DSwapChainImpl *Swapchain;
6291 HRESULT hr;
6293 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6295 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6296 if(hr != WINED3D_OK) {
6297 ERR("Can't get the swapchain\n");
6298 return hr;
6301 /* Make sure to release the swapchain */
6302 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6304 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6305 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6306 return WINED3DERR_INVALIDCALL;
6308 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6309 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6310 return WINED3DERR_INVALIDCALL;
6313 if(Swapchain->frontBuffer != Front) {
6314 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6316 if(Swapchain->frontBuffer)
6318 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6319 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
6321 Swapchain->frontBuffer = Front;
6323 if(Swapchain->frontBuffer) {
6324 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6325 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
6329 if(Back && !Swapchain->backBuffer) {
6330 /* We need memory for the back buffer array - only one back buffer this way */
6331 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6332 if(!Swapchain->backBuffer) {
6333 ERR("Out of memory\n");
6334 return E_OUTOFMEMORY;
6338 if(Swapchain->backBuffer[0] != Back) {
6339 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6341 /* What to do about the context here in the case of multithreading? Not sure.
6342 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6344 WARN("No active context?\n");
6346 ENTER_GL();
6347 if(!Swapchain->backBuffer[0]) {
6348 /* GL was told to draw to the front buffer at creation,
6349 * undo that
6351 glDrawBuffer(GL_BACK);
6352 checkGLcall("glDrawBuffer(GL_BACK)");
6353 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6354 Swapchain->presentParms.BackBufferCount = 1;
6355 } else if (!Back) {
6356 /* That makes problems - disable for now */
6357 /* glDrawBuffer(GL_FRONT); */
6358 checkGLcall("glDrawBuffer(GL_FRONT)");
6359 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6360 Swapchain->presentParms.BackBufferCount = 0;
6362 LEAVE_GL();
6364 if(Swapchain->backBuffer[0])
6366 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6367 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
6369 Swapchain->backBuffer[0] = Back;
6371 if(Swapchain->backBuffer[0]) {
6372 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6373 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
6374 } else {
6375 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6376 Swapchain->backBuffer = NULL;
6381 return WINED3D_OK;
6384 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6386 *ppZStencilSurface = This->stencilBufferTarget;
6387 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6389 if(*ppZStencilSurface != NULL) {
6390 /* Note inc ref on returned surface */
6391 IWineD3DSurface_AddRef(*ppZStencilSurface);
6392 return WINED3D_OK;
6393 } else {
6394 return WINED3DERR_NOTFOUND;
6398 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6399 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6401 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6402 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6403 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6404 struct wined3d_context *context;
6405 GLenum gl_filter;
6406 POINT offset = {0, 0};
6408 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6409 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6410 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6411 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6413 switch (filter) {
6414 case WINED3DTEXF_LINEAR:
6415 gl_filter = GL_LINEAR;
6416 break;
6418 default:
6419 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6420 case WINED3DTEXF_NONE:
6421 case WINED3DTEXF_POINT:
6422 gl_filter = GL_NEAREST;
6423 break;
6426 /* Attach src surface to src fbo */
6427 src_swapchain = get_swapchain(src_surface);
6428 dst_swapchain = get_swapchain(dst_surface);
6430 if (src_swapchain) context = ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6431 else if (dst_swapchain) context = ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6432 else context = ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6434 if (src_swapchain) {
6435 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6437 TRACE("Source surface %p is onscreen\n", src_surface);
6438 /* Make sure the drawable is up to date. In the offscreen case
6439 * attach_surface_fbo() implicitly takes care of this. */
6440 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6442 if(buffer == GL_FRONT) {
6443 RECT windowsize;
6444 UINT h;
6445 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6446 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6447 h = windowsize.bottom - windowsize.top;
6448 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6449 src_rect->y1 = offset.y + h - src_rect->y1;
6450 src_rect->y2 = offset.y + h - src_rect->y2;
6451 } else {
6452 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6453 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6456 ENTER_GL();
6457 context_bind_fbo(context, GL_READ_FRAMEBUFFER_EXT, NULL);
6458 glReadBuffer(buffer);
6459 checkGLcall("glReadBuffer()");
6460 } else {
6461 TRACE("Source surface %p is offscreen\n", src_surface);
6462 ENTER_GL();
6463 context_bind_fbo(context, GL_READ_FRAMEBUFFER_EXT, &context->src_fbo);
6464 context_attach_surface_fbo(context, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6465 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6466 checkGLcall("glReadBuffer()");
6467 context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER_EXT, NULL, FALSE);
6469 LEAVE_GL();
6471 /* Attach dst surface to dst fbo */
6472 if (dst_swapchain) {
6473 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6475 TRACE("Destination surface %p is onscreen\n", dst_surface);
6476 /* Make sure the drawable is up to date. In the offscreen case
6477 * attach_surface_fbo() implicitly takes care of this. */
6478 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6480 if(buffer == GL_FRONT) {
6481 RECT windowsize;
6482 UINT h;
6483 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6484 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6485 h = windowsize.bottom - windowsize.top;
6486 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6487 dst_rect->y1 = offset.y + h - dst_rect->y1;
6488 dst_rect->y2 = offset.y + h - dst_rect->y2;
6489 } else {
6490 /* Screen coords = window coords, surface height = window height */
6491 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6492 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6495 ENTER_GL();
6496 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER_EXT, NULL);
6497 glDrawBuffer(buffer);
6498 checkGLcall("glDrawBuffer()");
6499 } else {
6500 TRACE("Destination surface %p is offscreen\n", dst_surface);
6502 ENTER_GL();
6503 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER_EXT, &context->dst_fbo);
6504 context_attach_surface_fbo(context, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6505 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6506 checkGLcall("glDrawBuffer()");
6507 context_attach_depth_stencil_fbo(context, GL_DRAW_FRAMEBUFFER_EXT, NULL, FALSE);
6509 glDisable(GL_SCISSOR_TEST);
6510 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6512 if (flip) {
6513 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6514 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6515 checkGLcall("glBlitFramebuffer()");
6516 } else {
6517 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6518 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6519 checkGLcall("glBlitFramebuffer()");
6522 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6524 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6525 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6526 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6527 glDrawBuffer(GL_BACK);
6528 checkGLcall("glDrawBuffer()");
6530 LEAVE_GL();
6533 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6534 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6535 WINED3DVIEWPORT viewport;
6537 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6539 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6540 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6541 This, RenderTargetIndex, GL_LIMITS(buffers));
6542 return WINED3DERR_INVALIDCALL;
6545 /* MSDN says that null disables the render target
6546 but a device must always be associated with a render target
6547 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6549 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6550 FIXME("Trying to set render target 0 to NULL\n");
6551 return WINED3DERR_INVALIDCALL;
6553 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6554 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);
6555 return WINED3DERR_INVALIDCALL;
6558 /* If we are trying to set what we already have, don't bother */
6559 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6560 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6561 return WINED3D_OK;
6563 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6564 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6565 This->render_targets[RenderTargetIndex] = pRenderTarget;
6567 /* Render target 0 is special */
6568 if(RenderTargetIndex == 0) {
6569 /* Finally, reset the viewport as the MSDN states. */
6570 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6571 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6572 viewport.X = 0;
6573 viewport.Y = 0;
6574 viewport.MaxZ = 1.0f;
6575 viewport.MinZ = 0.0f;
6576 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6578 return WINED3D_OK;
6581 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6583 HRESULT hr = WINED3D_OK;
6584 IWineD3DSurface *tmp;
6586 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6588 if (pNewZStencil == This->stencilBufferTarget) {
6589 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6590 } else {
6591 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6592 * depending on the renter target implementation being used.
6593 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6594 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6595 * stencil buffer and incur an extra memory overhead
6596 ******************************************************/
6598 if (This->stencilBufferTarget) {
6599 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6600 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6601 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6602 } else {
6603 struct wined3d_context *context = ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6604 surface_load_ds_location(This->stencilBufferTarget, context, SFLAG_DS_OFFSCREEN);
6605 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6609 tmp = This->stencilBufferTarget;
6610 This->stencilBufferTarget = pNewZStencil;
6611 /* should we be calling the parent or the wined3d surface? */
6612 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6613 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6614 hr = WINED3D_OK;
6616 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6617 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6618 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6619 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6620 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6624 return hr;
6627 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6628 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6629 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6630 /* TODO: the use of Impl is deprecated. */
6631 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6632 WINED3DLOCKED_RECT lockedRect;
6634 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6636 /* some basic validation checks */
6637 if(This->cursorTexture) {
6638 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6639 ENTER_GL();
6640 glDeleteTextures(1, &This->cursorTexture);
6641 LEAVE_GL();
6642 This->cursorTexture = 0;
6645 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6646 This->haveHardwareCursor = TRUE;
6647 else
6648 This->haveHardwareCursor = FALSE;
6650 if(pCursorBitmap) {
6651 WINED3DLOCKED_RECT rect;
6653 /* MSDN: Cursor must be A8R8G8B8 */
6654 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format_desc->format)
6656 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6657 return WINED3DERR_INVALIDCALL;
6660 /* MSDN: Cursor must be smaller than the display mode */
6661 if(pSur->currentDesc.Width > This->ddraw_width ||
6662 pSur->currentDesc.Height > This->ddraw_height) {
6663 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);
6664 return WINED3DERR_INVALIDCALL;
6667 if (!This->haveHardwareCursor) {
6668 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6670 /* Do not store the surface's pointer because the application may
6671 * release it after setting the cursor image. Windows doesn't
6672 * addref the set surface, so we can't do this either without
6673 * creating circular refcount dependencies. Copy out the gl texture
6674 * instead.
6676 This->cursorWidth = pSur->currentDesc.Width;
6677 This->cursorHeight = pSur->currentDesc.Height;
6678 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6680 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION);
6681 char *mem, *bits = rect.pBits;
6682 GLint intfmt = glDesc->glInternal;
6683 GLint format = glDesc->glFormat;
6684 GLint type = glDesc->glType;
6685 INT height = This->cursorHeight;
6686 INT width = This->cursorWidth;
6687 INT bpp = glDesc->byte_count;
6688 DWORD sampler;
6689 INT i;
6691 /* Reformat the texture memory (pitch and width can be
6692 * different) */
6693 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6694 for(i = 0; i < height; i++)
6695 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6696 IWineD3DSurface_UnlockRect(pCursorBitmap);
6698 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6700 ENTER_GL();
6702 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6703 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6704 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6707 /* Make sure that a proper texture unit is selected */
6708 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6709 checkGLcall("glActiveTextureARB");
6710 sampler = This->rev_tex_unit_map[0];
6711 if (sampler != WINED3D_UNMAPPED_STAGE)
6713 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6715 /* Create a new cursor texture */
6716 glGenTextures(1, &This->cursorTexture);
6717 checkGLcall("glGenTextures");
6718 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6719 checkGLcall("glBindTexture");
6720 /* Copy the bitmap memory into the cursor texture */
6721 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6722 HeapFree(GetProcessHeap(), 0, mem);
6723 checkGLcall("glTexImage2D");
6725 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6726 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6727 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6730 LEAVE_GL();
6732 else
6734 FIXME("A cursor texture was not returned.\n");
6735 This->cursorTexture = 0;
6738 else
6740 /* Draw a hardware cursor */
6741 ICONINFO cursorInfo;
6742 HCURSOR cursor;
6743 /* Create and clear maskBits because it is not needed for
6744 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6745 * chunks. */
6746 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6747 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6748 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6749 WINED3DLOCK_NO_DIRTY_UPDATE |
6750 WINED3DLOCK_READONLY
6752 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6753 pSur->currentDesc.Height);
6755 cursorInfo.fIcon = FALSE;
6756 cursorInfo.xHotspot = XHotSpot;
6757 cursorInfo.yHotspot = YHotSpot;
6758 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6759 pSur->currentDesc.Height, 1,
6760 1, &maskBits);
6761 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6762 pSur->currentDesc.Height, 1,
6763 32, lockedRect.pBits);
6764 IWineD3DSurface_UnlockRect(pCursorBitmap);
6765 /* Create our cursor and clean up. */
6766 cursor = CreateIconIndirect(&cursorInfo);
6767 SetCursor(cursor);
6768 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6769 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6770 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6771 This->hardwareCursor = cursor;
6772 HeapFree(GetProcessHeap(), 0, maskBits);
6776 This->xHotSpot = XHotSpot;
6777 This->yHotSpot = YHotSpot;
6778 return WINED3D_OK;
6781 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6782 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6783 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6785 This->xScreenSpace = XScreenSpace;
6786 This->yScreenSpace = YScreenSpace;
6788 return;
6792 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6793 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6794 BOOL oldVisible = This->bCursorVisible;
6795 POINT pt;
6797 TRACE("(%p) : visible(%d)\n", This, bShow);
6800 * When ShowCursor is first called it should make the cursor appear at the OS's last
6801 * known cursor position. Because of this, some applications just repetitively call
6802 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6804 GetCursorPos(&pt);
6805 This->xScreenSpace = pt.x;
6806 This->yScreenSpace = pt.y;
6808 if (This->haveHardwareCursor) {
6809 This->bCursorVisible = bShow;
6810 if (bShow)
6811 SetCursor(This->hardwareCursor);
6812 else
6813 SetCursor(NULL);
6815 else
6817 if (This->cursorTexture)
6818 This->bCursorVisible = bShow;
6821 return oldVisible;
6824 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6825 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6826 IWineD3DResourceImpl *resource;
6827 TRACE("(%p) : state (%u)\n", This, This->state);
6829 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6830 switch (This->state) {
6831 case WINED3D_OK:
6832 return WINED3D_OK;
6833 case WINED3DERR_DEVICELOST:
6835 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6836 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6837 return WINED3DERR_DEVICENOTRESET;
6839 return WINED3DERR_DEVICELOST;
6841 case WINED3DERR_DRIVERINTERNALERROR:
6842 return WINED3DERR_DRIVERINTERNALERROR;
6845 /* Unknown state */
6846 return WINED3DERR_DRIVERINTERNALERROR;
6849 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6850 TRACE("checking resource %p for eviction\n", resource);
6851 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6852 TRACE("Evicting %p\n", resource);
6853 IWineD3DResource_UnLoad(resource);
6855 IWineD3DResource_Release(resource);
6856 return S_OK;
6859 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6860 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6861 TRACE("(%p)\n", This);
6863 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6864 return WINED3D_OK;
6867 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6869 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6871 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6872 if(surface->Flags & SFLAG_DIBSECTION) {
6873 /* Release the DC */
6874 SelectObject(surface->hDC, surface->dib.holdbitmap);
6875 DeleteDC(surface->hDC);
6876 /* Release the DIB section */
6877 DeleteObject(surface->dib.DIBsection);
6878 surface->dib.bitmap_data = NULL;
6879 surface->resource.allocatedMemory = NULL;
6880 surface->Flags &= ~SFLAG_DIBSECTION;
6882 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6883 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6884 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
6885 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
6886 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6887 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6888 } else {
6889 surface->pow2Width = surface->pow2Height = 1;
6890 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6891 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6893 surface->glRect.left = 0;
6894 surface->glRect.top = 0;
6895 surface->glRect.right = surface->pow2Width;
6896 surface->glRect.bottom = surface->pow2Height;
6898 if (surface->texture_name)
6900 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6901 ENTER_GL();
6902 glDeleteTextures(1, &surface->texture_name);
6903 LEAVE_GL();
6904 surface->texture_name = 0;
6905 surface->Flags &= ~SFLAG_CLIENT;
6907 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6908 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6909 surface->Flags |= SFLAG_NONPOW2;
6910 } else {
6911 surface->Flags &= ~SFLAG_NONPOW2;
6913 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6914 surface->resource.allocatedMemory = NULL;
6915 surface->resource.heapMemory = NULL;
6916 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6917 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
6918 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
6919 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
6920 } else {
6921 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
6925 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6926 TRACE("Unloading resource %p\n", resource);
6927 IWineD3DResource_UnLoad(resource);
6928 IWineD3DResource_Release(resource);
6929 return S_OK;
6932 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6934 UINT i, count;
6935 WINED3DDISPLAYMODE m;
6936 HRESULT hr;
6938 /* All Windowed modes are supported, as is leaving the current mode */
6939 if(pp->Windowed) return TRUE;
6940 if(!pp->BackBufferWidth) return TRUE;
6941 if(!pp->BackBufferHeight) return TRUE;
6943 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
6944 for(i = 0; i < count; i++) {
6945 memset(&m, 0, sizeof(m));
6946 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
6947 if(FAILED(hr)) {
6948 ERR("EnumAdapterModes failed\n");
6950 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6951 /* Mode found, it is supported */
6952 return TRUE;
6955 /* Mode not found -> not supported */
6956 return FALSE;
6959 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6960 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6961 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6962 UINT i;
6963 IWineD3DBaseShaderImpl *shader;
6965 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6967 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6968 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6969 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6972 ENTER_GL();
6973 if(This->depth_blt_texture) {
6974 glDeleteTextures(1, &This->depth_blt_texture);
6975 This->depth_blt_texture = 0;
6977 if (This->depth_blt_rb) {
6978 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
6979 This->depth_blt_rb = 0;
6980 This->depth_blt_rb_w = 0;
6981 This->depth_blt_rb_h = 0;
6983 LEAVE_GL();
6985 This->blitter->free_private(iface);
6986 This->frag_pipe->free_private(iface);
6987 This->shader_backend->shader_free_private(iface);
6989 ENTER_GL();
6990 for (i = 0; i < GL_LIMITS(textures); i++) {
6991 /* Textures are recreated below */
6992 glDeleteTextures(1, &This->dummyTextureName[i]);
6993 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
6994 This->dummyTextureName[i] = 0;
6996 LEAVE_GL();
6998 while(This->numContexts) {
6999 DestroyContext(This, This->contexts[0]);
7001 HeapFree(GetProcessHeap(), 0, swapchain->context);
7002 swapchain->context = NULL;
7003 swapchain->num_contexts = 0;
7006 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7007 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7008 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7009 HRESULT hr;
7010 IWineD3DSurfaceImpl *target;
7012 /* Recreate the primary swapchain's context */
7013 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7014 if(swapchain->backBuffer) {
7015 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7016 } else {
7017 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7019 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7020 &swapchain->presentParms);
7021 swapchain->num_contexts = 1;
7023 create_dummy_textures(This);
7025 hr = This->shader_backend->shader_alloc_private(iface);
7026 if(FAILED(hr)) {
7027 ERR("Failed to recreate shader private data\n");
7028 goto err_out;
7030 hr = This->frag_pipe->alloc_private(iface);
7031 if(FAILED(hr)) {
7032 TRACE("Fragment pipeline private data couldn't be allocated\n");
7033 goto err_out;
7035 hr = This->blitter->alloc_private(iface);
7036 if(FAILED(hr)) {
7037 TRACE("Blitter private data couldn't be allocated\n");
7038 goto err_out;
7041 return WINED3D_OK;
7043 err_out:
7044 This->blitter->free_private(iface);
7045 This->frag_pipe->free_private(iface);
7046 This->shader_backend->shader_free_private(iface);
7047 return hr;
7050 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7051 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7052 IWineD3DSwapChainImpl *swapchain;
7053 HRESULT hr;
7054 BOOL DisplayModeChanged = FALSE;
7055 WINED3DDISPLAYMODE mode;
7056 TRACE("(%p)\n", This);
7058 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7059 if(FAILED(hr)) {
7060 ERR("Failed to get the first implicit swapchain\n");
7061 return hr;
7064 if(!is_display_mode_supported(This, pPresentationParameters)) {
7065 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7066 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7067 pPresentationParameters->BackBufferHeight);
7068 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
7069 return WINED3DERR_INVALIDCALL;
7072 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7073 * on an existing gl context, so there's no real need for recreation.
7075 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7077 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7079 TRACE("New params:\n");
7080 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7081 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7082 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7083 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7084 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7085 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7086 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7087 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7088 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7089 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7090 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7091 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7092 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7094 /* No special treatment of these parameters. Just store them */
7095 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7096 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7097 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7098 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7100 /* What to do about these? */
7101 if(pPresentationParameters->BackBufferCount != 0 &&
7102 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7103 ERR("Cannot change the back buffer count yet\n");
7105 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7106 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7107 ERR("Cannot change the back buffer format yet\n");
7109 if(pPresentationParameters->hDeviceWindow != NULL &&
7110 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7111 ERR("Cannot change the device window yet\n");
7113 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7114 HRESULT hrc;
7116 TRACE("Creating the depth stencil buffer\n");
7118 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
7119 This->parent,
7120 pPresentationParameters->BackBufferWidth,
7121 pPresentationParameters->BackBufferHeight,
7122 pPresentationParameters->AutoDepthStencilFormat,
7123 pPresentationParameters->MultiSampleType,
7124 pPresentationParameters->MultiSampleQuality,
7125 FALSE,
7126 &This->auto_depth_stencil_buffer);
7128 if (FAILED(hrc)) {
7129 ERR("Failed to create the depth stencil buffer\n");
7130 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7131 return WINED3DERR_INVALIDCALL;
7135 /* Reset the depth stencil */
7136 if (pPresentationParameters->EnableAutoDepthStencil)
7137 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7138 else
7139 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7141 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7143 if(pPresentationParameters->Windowed) {
7144 mode.Width = swapchain->orig_width;
7145 mode.Height = swapchain->orig_height;
7146 mode.RefreshRate = 0;
7147 mode.Format = swapchain->presentParms.BackBufferFormat;
7148 } else {
7149 mode.Width = pPresentationParameters->BackBufferWidth;
7150 mode.Height = pPresentationParameters->BackBufferHeight;
7151 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7152 mode.Format = swapchain->presentParms.BackBufferFormat;
7155 /* Should Width == 800 && Height == 0 set 800x600? */
7156 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7157 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7158 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7160 UINT i;
7162 if(!pPresentationParameters->Windowed) {
7163 DisplayModeChanged = TRUE;
7165 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7166 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7168 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7169 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7170 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7172 if(This->auto_depth_stencil_buffer) {
7173 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7177 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7178 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7179 DisplayModeChanged) {
7181 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7183 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7184 if(swapchain->presentParms.Windowed) {
7185 /* switch from windowed to fs */
7186 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7187 pPresentationParameters->BackBufferWidth,
7188 pPresentationParameters->BackBufferHeight);
7189 } else {
7190 /* Fullscreen -> fullscreen mode change */
7191 MoveWindow(swapchain->win_handle, 0, 0,
7192 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7193 TRUE);
7195 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7196 /* Fullscreen -> windowed switch */
7197 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7199 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7200 } else if(!pPresentationParameters->Windowed) {
7201 DWORD style = This->style, exStyle = This->exStyle;
7202 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7203 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7204 * Reset to clear up their mess. Guild Wars also loses the device during that.
7206 This->style = 0;
7207 This->exStyle = 0;
7208 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7209 pPresentationParameters->BackBufferWidth,
7210 pPresentationParameters->BackBufferHeight);
7211 This->style = style;
7212 This->exStyle = exStyle;
7215 TRACE("Resetting stateblock\n");
7216 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
7217 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
7219 /* Note: No parent needed for initial internal stateblock */
7220 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
7221 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7222 else TRACE("Created stateblock %p\n", This->stateBlock);
7223 This->updateStateBlock = This->stateBlock;
7224 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
7226 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7227 if(FAILED(hr)) {
7228 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7231 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7232 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7234 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7235 * first use
7237 return hr;
7240 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7242 /** FIXME: always true at the moment **/
7243 if(!bEnableDialogs) {
7244 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7246 return WINED3D_OK;
7250 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7252 TRACE("(%p) : pParameters %p\n", This, pParameters);
7254 *pParameters = This->createParms;
7255 return WINED3D_OK;
7258 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7259 IWineD3DSwapChain *swapchain;
7261 TRACE("Relaying to swapchain\n");
7263 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7264 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7265 IWineD3DSwapChain_Release(swapchain);
7267 return;
7270 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7271 IWineD3DSwapChain *swapchain;
7273 TRACE("Relaying to swapchain\n");
7275 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7276 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7277 IWineD3DSwapChain_Release(swapchain);
7279 return;
7283 /** ********************************************************
7284 * Notification functions
7285 ** ********************************************************/
7286 /** This function must be called in the release of a resource when ref == 0,
7287 * the contents of resource must still be correct,
7288 * any handles to other resource held by the caller must be closed
7289 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7290 *****************************************************/
7291 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7293 TRACE("(%p) : Adding resource %p\n", This, resource);
7295 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7298 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7300 TRACE("(%p) : Removing resource %p\n", This, resource);
7302 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7305 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7307 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7308 int counter;
7310 TRACE("(%p) : resource %p\n", This, resource);
7312 context_resource_released((IWineD3DDevice *)This, resource, type);
7314 switch (type) {
7315 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7316 case WINED3DRTYPE_SURFACE: {
7317 unsigned int i;
7319 if (This->d3d_initialized)
7321 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7322 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7323 This->render_targets[i] = NULL;
7326 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7327 This->stencilBufferTarget = NULL;
7331 break;
7333 case WINED3DRTYPE_TEXTURE:
7334 case WINED3DRTYPE_CUBETEXTURE:
7335 case WINED3DRTYPE_VOLUMETEXTURE:
7336 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7337 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7338 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7339 This->stateBlock->textures[counter] = NULL;
7341 if (This->updateStateBlock != This->stateBlock ){
7342 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7343 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7344 This->updateStateBlock->textures[counter] = NULL;
7348 break;
7349 case WINED3DRTYPE_VOLUME:
7350 /* TODO: nothing really? */
7351 break;
7352 case WINED3DRTYPE_BUFFER:
7354 int streamNumber;
7355 TRACE("Cleaning up stream pointers\n");
7357 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7358 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7359 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7361 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7362 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7363 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7364 This->updateStateBlock->streamSource[streamNumber] = 0;
7365 /* Set changed flag? */
7368 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) */
7369 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7370 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7371 This->stateBlock->streamSource[streamNumber] = 0;
7376 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7377 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7378 This->updateStateBlock->pIndexData = NULL;
7381 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7382 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7383 This->stateBlock->pIndexData = NULL;
7387 break;
7389 default:
7390 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7391 break;
7395 /* Remove the resource from the resourceStore */
7396 device_resource_remove(This, resource);
7398 TRACE("Resource released\n");
7402 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7403 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7404 IWineD3DResourceImpl *resource, *cursor;
7405 HRESULT ret;
7406 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7408 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7409 TRACE("enumerating resource %p\n", resource);
7410 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7411 ret = pCallback((IWineD3DResource *) resource, pData);
7412 if(ret == S_FALSE) {
7413 TRACE("Canceling enumeration\n");
7414 break;
7417 return WINED3D_OK;
7420 /**********************************************************
7421 * IWineD3DDevice VTbl follows
7422 **********************************************************/
7424 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7426 /*** IUnknown methods ***/
7427 IWineD3DDeviceImpl_QueryInterface,
7428 IWineD3DDeviceImpl_AddRef,
7429 IWineD3DDeviceImpl_Release,
7430 /*** IWineD3DDevice methods ***/
7431 IWineD3DDeviceImpl_GetParent,
7432 /*** Creation methods**/
7433 IWineD3DDeviceImpl_CreateBuffer,
7434 IWineD3DDeviceImpl_CreateVertexBuffer,
7435 IWineD3DDeviceImpl_CreateIndexBuffer,
7436 IWineD3DDeviceImpl_CreateStateBlock,
7437 IWineD3DDeviceImpl_CreateSurface,
7438 IWineD3DDeviceImpl_CreateRendertargetView,
7439 IWineD3DDeviceImpl_CreateTexture,
7440 IWineD3DDeviceImpl_CreateVolumeTexture,
7441 IWineD3DDeviceImpl_CreateVolume,
7442 IWineD3DDeviceImpl_CreateCubeTexture,
7443 IWineD3DDeviceImpl_CreateQuery,
7444 IWineD3DDeviceImpl_CreateSwapChain,
7445 IWineD3DDeviceImpl_CreateVertexDeclaration,
7446 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7447 IWineD3DDeviceImpl_CreateVertexShader,
7448 IWineD3DDeviceImpl_CreatePixelShader,
7449 IWineD3DDeviceImpl_CreatePalette,
7450 /*** Odd functions **/
7451 IWineD3DDeviceImpl_Init3D,
7452 IWineD3DDeviceImpl_InitGDI,
7453 IWineD3DDeviceImpl_Uninit3D,
7454 IWineD3DDeviceImpl_UninitGDI,
7455 IWineD3DDeviceImpl_SetMultithreaded,
7456 IWineD3DDeviceImpl_EvictManagedResources,
7457 IWineD3DDeviceImpl_GetAvailableTextureMem,
7458 IWineD3DDeviceImpl_GetBackBuffer,
7459 IWineD3DDeviceImpl_GetCreationParameters,
7460 IWineD3DDeviceImpl_GetDeviceCaps,
7461 IWineD3DDeviceImpl_GetDirect3D,
7462 IWineD3DDeviceImpl_GetDisplayMode,
7463 IWineD3DDeviceImpl_SetDisplayMode,
7464 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7465 IWineD3DDeviceImpl_GetRasterStatus,
7466 IWineD3DDeviceImpl_GetSwapChain,
7467 IWineD3DDeviceImpl_Reset,
7468 IWineD3DDeviceImpl_SetDialogBoxMode,
7469 IWineD3DDeviceImpl_SetCursorProperties,
7470 IWineD3DDeviceImpl_SetCursorPosition,
7471 IWineD3DDeviceImpl_ShowCursor,
7472 IWineD3DDeviceImpl_TestCooperativeLevel,
7473 /*** Getters and setters **/
7474 IWineD3DDeviceImpl_SetClipPlane,
7475 IWineD3DDeviceImpl_GetClipPlane,
7476 IWineD3DDeviceImpl_SetClipStatus,
7477 IWineD3DDeviceImpl_GetClipStatus,
7478 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7479 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7480 IWineD3DDeviceImpl_SetDepthStencilSurface,
7481 IWineD3DDeviceImpl_GetDepthStencilSurface,
7482 IWineD3DDeviceImpl_SetGammaRamp,
7483 IWineD3DDeviceImpl_GetGammaRamp,
7484 IWineD3DDeviceImpl_SetIndices,
7485 IWineD3DDeviceImpl_GetIndices,
7486 IWineD3DDeviceImpl_SetBaseVertexIndex,
7487 IWineD3DDeviceImpl_GetBaseVertexIndex,
7488 IWineD3DDeviceImpl_SetLight,
7489 IWineD3DDeviceImpl_GetLight,
7490 IWineD3DDeviceImpl_SetLightEnable,
7491 IWineD3DDeviceImpl_GetLightEnable,
7492 IWineD3DDeviceImpl_SetMaterial,
7493 IWineD3DDeviceImpl_GetMaterial,
7494 IWineD3DDeviceImpl_SetNPatchMode,
7495 IWineD3DDeviceImpl_GetNPatchMode,
7496 IWineD3DDeviceImpl_SetPaletteEntries,
7497 IWineD3DDeviceImpl_GetPaletteEntries,
7498 IWineD3DDeviceImpl_SetPixelShader,
7499 IWineD3DDeviceImpl_GetPixelShader,
7500 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7501 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7502 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7503 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7504 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7505 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7506 IWineD3DDeviceImpl_SetRenderState,
7507 IWineD3DDeviceImpl_GetRenderState,
7508 IWineD3DDeviceImpl_SetRenderTarget,
7509 IWineD3DDeviceImpl_GetRenderTarget,
7510 IWineD3DDeviceImpl_SetFrontBackBuffers,
7511 IWineD3DDeviceImpl_SetSamplerState,
7512 IWineD3DDeviceImpl_GetSamplerState,
7513 IWineD3DDeviceImpl_SetScissorRect,
7514 IWineD3DDeviceImpl_GetScissorRect,
7515 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7516 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7517 IWineD3DDeviceImpl_SetStreamSource,
7518 IWineD3DDeviceImpl_GetStreamSource,
7519 IWineD3DDeviceImpl_SetStreamSourceFreq,
7520 IWineD3DDeviceImpl_GetStreamSourceFreq,
7521 IWineD3DDeviceImpl_SetTexture,
7522 IWineD3DDeviceImpl_GetTexture,
7523 IWineD3DDeviceImpl_SetTextureStageState,
7524 IWineD3DDeviceImpl_GetTextureStageState,
7525 IWineD3DDeviceImpl_SetTransform,
7526 IWineD3DDeviceImpl_GetTransform,
7527 IWineD3DDeviceImpl_SetVertexDeclaration,
7528 IWineD3DDeviceImpl_GetVertexDeclaration,
7529 IWineD3DDeviceImpl_SetVertexShader,
7530 IWineD3DDeviceImpl_GetVertexShader,
7531 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7532 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7533 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7534 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7535 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7536 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7537 IWineD3DDeviceImpl_SetViewport,
7538 IWineD3DDeviceImpl_GetViewport,
7539 IWineD3DDeviceImpl_MultiplyTransform,
7540 IWineD3DDeviceImpl_ValidateDevice,
7541 IWineD3DDeviceImpl_ProcessVertices,
7542 /*** State block ***/
7543 IWineD3DDeviceImpl_BeginStateBlock,
7544 IWineD3DDeviceImpl_EndStateBlock,
7545 /*** Scene management ***/
7546 IWineD3DDeviceImpl_BeginScene,
7547 IWineD3DDeviceImpl_EndScene,
7548 IWineD3DDeviceImpl_Present,
7549 IWineD3DDeviceImpl_Clear,
7550 IWineD3DDeviceImpl_ClearRendertargetView,
7551 /*** Drawing ***/
7552 IWineD3DDeviceImpl_SetPrimitiveType,
7553 IWineD3DDeviceImpl_GetPrimitiveType,
7554 IWineD3DDeviceImpl_DrawPrimitive,
7555 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7556 IWineD3DDeviceImpl_DrawPrimitiveUP,
7557 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7558 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7559 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7560 IWineD3DDeviceImpl_DrawRectPatch,
7561 IWineD3DDeviceImpl_DrawTriPatch,
7562 IWineD3DDeviceImpl_DeletePatch,
7563 IWineD3DDeviceImpl_ColorFill,
7564 IWineD3DDeviceImpl_UpdateTexture,
7565 IWineD3DDeviceImpl_UpdateSurface,
7566 IWineD3DDeviceImpl_GetFrontBufferData,
7567 /*** object tracking ***/
7568 IWineD3DDeviceImpl_EnumResources
7571 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7572 WINED3DRS_ALPHABLENDENABLE ,
7573 WINED3DRS_ALPHAFUNC ,
7574 WINED3DRS_ALPHAREF ,
7575 WINED3DRS_ALPHATESTENABLE ,
7576 WINED3DRS_BLENDOP ,
7577 WINED3DRS_COLORWRITEENABLE ,
7578 WINED3DRS_DESTBLEND ,
7579 WINED3DRS_DITHERENABLE ,
7580 WINED3DRS_FILLMODE ,
7581 WINED3DRS_FOGDENSITY ,
7582 WINED3DRS_FOGEND ,
7583 WINED3DRS_FOGSTART ,
7584 WINED3DRS_LASTPIXEL ,
7585 WINED3DRS_SHADEMODE ,
7586 WINED3DRS_SRCBLEND ,
7587 WINED3DRS_STENCILENABLE ,
7588 WINED3DRS_STENCILFAIL ,
7589 WINED3DRS_STENCILFUNC ,
7590 WINED3DRS_STENCILMASK ,
7591 WINED3DRS_STENCILPASS ,
7592 WINED3DRS_STENCILREF ,
7593 WINED3DRS_STENCILWRITEMASK ,
7594 WINED3DRS_STENCILZFAIL ,
7595 WINED3DRS_TEXTUREFACTOR ,
7596 WINED3DRS_WRAP0 ,
7597 WINED3DRS_WRAP1 ,
7598 WINED3DRS_WRAP2 ,
7599 WINED3DRS_WRAP3 ,
7600 WINED3DRS_WRAP4 ,
7601 WINED3DRS_WRAP5 ,
7602 WINED3DRS_WRAP6 ,
7603 WINED3DRS_WRAP7 ,
7604 WINED3DRS_ZENABLE ,
7605 WINED3DRS_ZFUNC ,
7606 WINED3DRS_ZWRITEENABLE
7609 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7610 WINED3DTSS_ALPHAARG0 ,
7611 WINED3DTSS_ALPHAARG1 ,
7612 WINED3DTSS_ALPHAARG2 ,
7613 WINED3DTSS_ALPHAOP ,
7614 WINED3DTSS_BUMPENVLOFFSET ,
7615 WINED3DTSS_BUMPENVLSCALE ,
7616 WINED3DTSS_BUMPENVMAT00 ,
7617 WINED3DTSS_BUMPENVMAT01 ,
7618 WINED3DTSS_BUMPENVMAT10 ,
7619 WINED3DTSS_BUMPENVMAT11 ,
7620 WINED3DTSS_COLORARG0 ,
7621 WINED3DTSS_COLORARG1 ,
7622 WINED3DTSS_COLORARG2 ,
7623 WINED3DTSS_COLOROP ,
7624 WINED3DTSS_RESULTARG ,
7625 WINED3DTSS_TEXCOORDINDEX ,
7626 WINED3DTSS_TEXTURETRANSFORMFLAGS
7629 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7630 WINED3DSAMP_ADDRESSU ,
7631 WINED3DSAMP_ADDRESSV ,
7632 WINED3DSAMP_ADDRESSW ,
7633 WINED3DSAMP_BORDERCOLOR ,
7634 WINED3DSAMP_MAGFILTER ,
7635 WINED3DSAMP_MINFILTER ,
7636 WINED3DSAMP_MIPFILTER ,
7637 WINED3DSAMP_MIPMAPLODBIAS ,
7638 WINED3DSAMP_MAXMIPLEVEL ,
7639 WINED3DSAMP_MAXANISOTROPY ,
7640 WINED3DSAMP_SRGBTEXTURE ,
7641 WINED3DSAMP_ELEMENTINDEX
7644 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7645 WINED3DRS_AMBIENT ,
7646 WINED3DRS_AMBIENTMATERIALSOURCE ,
7647 WINED3DRS_CLIPPING ,
7648 WINED3DRS_CLIPPLANEENABLE ,
7649 WINED3DRS_COLORVERTEX ,
7650 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7651 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7652 WINED3DRS_FOGDENSITY ,
7653 WINED3DRS_FOGEND ,
7654 WINED3DRS_FOGSTART ,
7655 WINED3DRS_FOGTABLEMODE ,
7656 WINED3DRS_FOGVERTEXMODE ,
7657 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7658 WINED3DRS_LIGHTING ,
7659 WINED3DRS_LOCALVIEWER ,
7660 WINED3DRS_MULTISAMPLEANTIALIAS ,
7661 WINED3DRS_MULTISAMPLEMASK ,
7662 WINED3DRS_NORMALIZENORMALS ,
7663 WINED3DRS_PATCHEDGESTYLE ,
7664 WINED3DRS_POINTSCALE_A ,
7665 WINED3DRS_POINTSCALE_B ,
7666 WINED3DRS_POINTSCALE_C ,
7667 WINED3DRS_POINTSCALEENABLE ,
7668 WINED3DRS_POINTSIZE ,
7669 WINED3DRS_POINTSIZE_MAX ,
7670 WINED3DRS_POINTSIZE_MIN ,
7671 WINED3DRS_POINTSPRITEENABLE ,
7672 WINED3DRS_RANGEFOGENABLE ,
7673 WINED3DRS_SPECULARMATERIALSOURCE ,
7674 WINED3DRS_TWEENFACTOR ,
7675 WINED3DRS_VERTEXBLEND ,
7676 WINED3DRS_CULLMODE ,
7677 WINED3DRS_FOGCOLOR
7680 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7681 WINED3DTSS_TEXCOORDINDEX ,
7682 WINED3DTSS_TEXTURETRANSFORMFLAGS
7685 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7686 WINED3DSAMP_DMAPOFFSET
7689 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7690 DWORD rep = This->StateTable[state].representative;
7691 struct wined3d_context *context;
7692 DWORD idx;
7693 BYTE shift;
7694 UINT i;
7696 for(i = 0; i < This->numContexts; i++) {
7697 context = This->contexts[i];
7698 if(isStateDirty(context, rep)) continue;
7700 context->dirtyArray[context->numDirtyEntries++] = rep;
7701 idx = rep >> 5;
7702 shift = rep & 0x1f;
7703 context->isStateDirty[idx] |= (1 << shift);
7707 void get_drawable_size_pbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7709 IWineD3DDeviceImpl *device = ((IWineD3DSurfaceImpl *)context->current_rt)->resource.wineD3DDevice;
7710 /* The drawable size of a pbuffer render target is the current pbuffer size. */
7711 *width = device->pbufferWidth;
7712 *height = device->pbufferHeight;
7715 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7717 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->current_rt;
7718 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7719 *width = surface->pow2Width;
7720 *height = surface->pow2Height;
7723 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7725 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->surface;
7726 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7727 * current context's drawable, which is the size of the back buffer of the swapchain
7728 * the active context belongs to. The back buffer of the swapchain is stored as the
7729 * surface the context belongs to. */
7730 *width = surface->currentDesc.Width;
7731 *height = surface->currentDesc.Height;