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
12 * Copyright 2009 Henri Verbeet for CodeWeavers
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
34 #include "wined3d_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
37 #define GLINFO_LOCATION This->adapter->gl_info
39 /* Define the default light parameters as specified by MSDN */
40 const WINED3DLIGHT WINED3D_default_light = {
42 WINED3DLIGHT_DIRECTIONAL, /* Type */
43 { 1.0f, 1.0f, 1.0f, 0.0f }, /* Diffuse r,g,b,a */
44 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Specular r,g,b,a */
45 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Ambient r,g,b,a, */
46 { 0.0f, 0.0f, 0.0f }, /* Position x,y,z */
47 { 0.0f, 0.0f, 1.0f }, /* Direction x,y,z */
50 0.0f, 0.0f, 0.0f, /* Attenuation 0,1,2 */
55 /**********************************************************
56 * Global variable / Constants follow
57 **********************************************************/
58 const float identity[] =
60 1.0f, 0.0f, 0.0f, 0.0f,
61 0.0f, 1.0f, 0.0f, 0.0f,
62 0.0f, 0.0f, 1.0f, 0.0f,
63 0.0f, 0.0f, 0.0f, 1.0f,
64 }; /* When needed for comparisons */
66 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
67 * actually have the same values in GL and D3D. */
68 static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
70 switch(primitive_type)
72 case WINED3DPT_POINTLIST:
75 case WINED3DPT_LINELIST:
78 case WINED3DPT_LINESTRIP:
81 case WINED3DPT_TRIANGLELIST:
84 case WINED3DPT_TRIANGLESTRIP:
85 return GL_TRIANGLE_STRIP;
87 case WINED3DPT_TRIANGLEFAN:
88 return GL_TRIANGLE_FAN;
90 case WINED3DPT_LINELIST_ADJ:
91 return GL_LINES_ADJACENCY_ARB;
93 case WINED3DPT_LINESTRIP_ADJ:
94 return GL_LINE_STRIP_ADJACENCY_ARB;
96 case WINED3DPT_TRIANGLELIST_ADJ:
97 return GL_TRIANGLES_ADJACENCY_ARB;
99 case WINED3DPT_TRIANGLESTRIP_ADJ:
100 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
103 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
108 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
110 switch(primitive_type)
113 return WINED3DPT_POINTLIST;
116 return WINED3DPT_LINELIST;
119 return WINED3DPT_LINESTRIP;
122 return WINED3DPT_TRIANGLELIST;
124 case GL_TRIANGLE_STRIP:
125 return WINED3DPT_TRIANGLESTRIP;
127 case GL_TRIANGLE_FAN:
128 return WINED3DPT_TRIANGLEFAN;
130 case GL_LINES_ADJACENCY_ARB:
131 return WINED3DPT_LINELIST_ADJ;
133 case GL_LINE_STRIP_ADJACENCY_ARB:
134 return WINED3DPT_LINESTRIP_ADJ;
136 case GL_TRIANGLES_ADJACENCY_ARB:
137 return WINED3DPT_TRIANGLELIST_ADJ;
139 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
140 return WINED3DPT_TRIANGLESTRIP_ADJ;
143 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
144 return WINED3DPT_UNDEFINED;
148 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
150 if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && usage_idx == 0)
151 *regnum = WINED3D_FFP_POSITION;
152 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
153 *regnum = WINED3D_FFP_BLENDWEIGHT;
154 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
155 *regnum = WINED3D_FFP_BLENDINDICES;
156 else if (usage == WINED3DDECLUSAGE_NORMAL && usage_idx == 0)
157 *regnum = WINED3D_FFP_NORMAL;
158 else if (usage == WINED3DDECLUSAGE_PSIZE && usage_idx == 0)
159 *regnum = WINED3D_FFP_PSIZE;
160 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 0)
161 *regnum = WINED3D_FFP_DIFFUSE;
162 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1)
163 *regnum = WINED3D_FFP_SPECULAR;
164 else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
165 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
168 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
176 /* Context activation is done by the caller. */
177 void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
178 BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
180 /* We need to deal with frequency data! */
181 IWineD3DVertexDeclarationImpl *declaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
182 UINT stream_count = This->stateBlock->streamIsUP ? 0 : declaration->num_streams;
183 const DWORD *streams = declaration->streams;
186 stream_info->use_map = 0;
187 stream_info->swizzle_map = 0;
189 /* Check for transformed vertices, disable vertex shader if present. */
190 stream_info->position_transformed = declaration->position_transformed;
191 if (declaration->position_transformed) use_vshader = FALSE;
193 /* Translate the declaration into strided data. */
194 for (i = 0; i < declaration->element_count; ++i)
196 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
197 GLuint buffer_object = 0;
198 const BYTE *data = NULL;
203 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
204 element, i + 1, declaration->element_count);
206 if (!This->stateBlock->streamSource[element->input_slot]) continue;
208 stride = This->stateBlock->streamStride[element->input_slot];
209 if (This->stateBlock->streamIsUP)
211 TRACE("Stream %u is UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
213 data = (BYTE *)This->stateBlock->streamSource[element->input_slot];
217 TRACE("Stream %u isn't UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
218 data = buffer_get_memory(This->stateBlock->streamSource[element->input_slot], 0, &buffer_object);
220 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
221 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
222 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
223 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
224 * not, drawStridedSlow is needed, including a vertex buffer path. */
225 if (This->stateBlock->loadBaseVertexIndex < 0)
227 WARN("loadBaseVertexIndex is < 0 (%d), not using vbos\n", This->stateBlock->loadBaseVertexIndex);
229 data = buffer_get_sysmem((struct wined3d_buffer *)This->stateBlock->streamSource[element->input_slot]);
230 if ((UINT_PTR)data < -This->stateBlock->loadBaseVertexIndex * stride)
232 FIXME("System memory vertex data load offset is negative!\n");
238 if (buffer_object) *fixup = TRUE;
239 else if (*fixup && !use_vshader
240 && (element->usage == WINED3DDECLUSAGE_COLOR
241 || element->usage == WINED3DDECLUSAGE_POSITIONT))
243 static BOOL warned = FALSE;
246 /* This may be bad with the fixed function pipeline. */
247 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
253 data += element->offset;
255 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
259 if (element->output_slot == ~0U)
261 /* TODO: Assuming vertexdeclarations are usually used with the
262 * same or a similar shader, it might be worth it to store the
263 * last used output slot and try that one first. */
264 stride_used = vshader_get_input(This->stateBlock->vertexShader,
265 element->usage, element->usage_idx, &idx);
269 idx = element->output_slot;
275 if (!element->ffp_valid)
277 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
278 debug_d3dformat(element->format_desc->format), debug_d3ddeclusage(element->usage));
283 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
289 TRACE("Load %s array %u [usage %s, usage_idx %u, "
290 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
291 use_vshader ? "shader": "fixed function", idx,
292 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
293 element->offset, stride, debug_d3dformat(element->format_desc->format), buffer_object);
295 stream_info->elements[idx].format_desc = element->format_desc;
296 stream_info->elements[idx].stride = stride;
297 stream_info->elements[idx].data = data;
298 stream_info->elements[idx].stream_idx = element->input_slot;
299 stream_info->elements[idx].buffer_object = buffer_object;
301 if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA) && element->format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
303 stream_info->swizzle_map |= 1 << idx;
305 stream_info->use_map |= 1 << idx;
309 /* Now call PreLoad on all the vertex buffers. In the very rare case
310 * that the buffers stopps converting PreLoad will dirtify the VDECL again.
311 * The vertex buffer can now use the strided structure in the device instead of finding its
314 * NULL streams won't be recorded in the array, UP streams won't be either. A stream is only
316 for (i = 0; i < stream_count; ++i)
318 IWineD3DBuffer *vb = This->stateBlock->streamSource[streams[i]];
319 if (vb) IWineD3DBuffer_PreLoad(vb);
323 static void stream_info_element_from_strided(IWineD3DDeviceImpl *This,
324 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
326 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(strided->format, &This->adapter->gl_info);
327 e->format_desc = format_desc;
328 e->stride = strided->dwStride;
329 e->data = strided->lpData;
331 e->buffer_object = 0;
334 void device_stream_info_from_strided(IWineD3DDeviceImpl *This,
335 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
339 memset(stream_info, 0, sizeof(*stream_info));
341 if (strided->position.lpData)
342 stream_info_element_from_strided(This, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
343 if (strided->normal.lpData)
344 stream_info_element_from_strided(This, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
345 if (strided->diffuse.lpData)
346 stream_info_element_from_strided(This, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
347 if (strided->specular.lpData)
348 stream_info_element_from_strided(This, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
350 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
352 if (strided->texCoords[i].lpData)
353 stream_info_element_from_strided(This, &strided->texCoords[i],
354 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
357 stream_info->position_transformed = strided->position_transformed;
359 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
361 if (!stream_info->elements[i].format_desc) continue;
363 if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA)
364 && stream_info->elements[i].format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
366 stream_info->swizzle_map |= 1 << i;
368 stream_info->use_map |= 1 << i;
372 /**********************************************************
373 * IUnknown parts follows
374 **********************************************************/
376 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
380 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
381 if (IsEqualGUID(riid, &IID_IUnknown)
382 || IsEqualGUID(riid, &IID_IWineD3DBase)
383 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
384 IUnknown_AddRef(iface);
389 return E_NOINTERFACE;
392 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
393 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
394 ULONG refCount = InterlockedIncrement(&This->ref);
396 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
400 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
401 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
402 ULONG refCount = InterlockedDecrement(&This->ref);
404 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
409 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
410 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
411 This->multistate_funcs[i] = NULL;
414 /* TODO: Clean up all the surfaces and textures! */
415 /* NOTE: You must release the parent if the object was created via a callback
416 ** ***************************/
418 if (!list_empty(&This->resources)) {
419 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
420 dumpResources(&This->resources);
423 if(This->contexts) ERR("Context array not freed!\n");
424 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
425 This->haveHardwareCursor = FALSE;
427 IWineD3D_Release(This->wineD3D);
428 This->wineD3D = NULL;
429 HeapFree(GetProcessHeap(), 0, This);
430 TRACE("Freed device %p\n", This);
436 /**********************************************************
437 * IWineD3DDevice implementation follows
438 **********************************************************/
439 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
441 *pParent = This->parent;
442 IUnknown_AddRef(This->parent);
446 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
447 const void *data, IUnknown *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
449 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
450 struct wined3d_buffer *object;
453 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
455 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
458 ERR("Failed to allocate memory\n");
459 return E_OUTOFMEMORY;
462 FIXME("Ignoring access flags (pool)\n");
464 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
465 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
468 WARN("Failed to initialize buffer, hr %#x.\n", hr);
469 HeapFree(GetProcessHeap(), 0, object);
472 object->desc = *desc;
474 TRACE("Created buffer %p.\n", object);
476 *buffer = (IWineD3DBuffer *)object;
481 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size,
482 DWORD Usage, DWORD FVF, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer,
483 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
486 struct wined3d_buffer *object;
487 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
491 if (Pool == WINED3DPOOL_SCRATCH)
493 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
494 * anyway, SCRATCH vertex buffers aren't usable anywhere
496 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
497 *ppVertexBuffer = NULL;
498 return WINED3DERR_INVALIDCALL;
501 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
504 ERR("Out of memory\n");
505 *ppVertexBuffer = NULL;
506 return WINED3DERR_OUTOFVIDEOMEMORY;
509 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
510 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
513 WARN("Failed to initialize buffer, hr %#x.\n", hr);
514 HeapFree(GetProcessHeap(), 0, object);
518 TRACE("Created buffer %p.\n", object);
519 TRACE("FVF %#x, Pool %#x.\n", FVF, Pool);
520 *ppVertexBuffer = (IWineD3DBuffer *)object;
522 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
523 * drawStridedFast (half-life 2).
525 * Basically converting the vertices in the buffer is quite expensive, and observations
526 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
527 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
529 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
530 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
531 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
532 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
534 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
535 * more. In this call we can convert dx7 buffers too.
537 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
538 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
539 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
540 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
541 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
542 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
543 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
544 } else if(dxVersion <= 7 && conv) {
545 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
547 object->flags |= WINED3D_BUFFER_CREATEBO;
552 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
553 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer,
554 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
556 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
557 struct wined3d_buffer *object;
560 TRACE("(%p) Creating index buffer\n", This);
562 /* Allocate the storage for the device */
563 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
566 ERR("Out of memory\n");
567 *ppIndexBuffer = NULL;
568 return WINED3DERR_OUTOFVIDEOMEMORY;
571 hr = buffer_init(object, This, Length, Usage, WINED3DFMT_UNKNOWN,
572 Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
575 WARN("Failed to initialize buffer, hr %#x\n", hr);
576 HeapFree(GetProcessHeap(), 0, object);
580 TRACE("Created buffer %p.\n", object);
582 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
583 object->flags |= WINED3D_BUFFER_CREATEBO;
586 *ppIndexBuffer = (IWineD3DBuffer *) object;
591 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
593 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
594 IWineD3DStateBlockImpl *object;
598 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
601 ERR("Out of memory\n");
602 *ppStateBlock = NULL;
603 return WINED3DERR_OUTOFVIDEOMEMORY;
606 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
607 object->wineD3DDevice = This;
608 object->parent = parent;
610 object->blockType = Type;
612 *ppStateBlock = (IWineD3DStateBlock *)object;
614 for(i = 0; i < LIGHTMAP_SIZE; i++) {
615 list_init(&object->lightMap[i]);
618 temp_result = allocate_shader_constants(object);
619 if (FAILED(temp_result))
621 HeapFree(GetProcessHeap(), 0, object);
625 /* Special case - Used during initialization to produce a placeholder stateblock
626 so other functions called can update a state block */
627 if (Type == WINED3DSBT_INIT || Type == WINED3DSBT_RECORDED)
629 /* Don't bother increasing the reference count otherwise a device will never
630 be freed due to circular dependencies */
634 /* Otherwise, might as well set the whole state block to the appropriate values */
635 if (This->stateBlock != NULL)
636 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
638 memset(object->streamFreq, 1, sizeof(object->streamFreq));
640 /* Reset the ref and type after kludging it */
641 object->wineD3DDevice = This;
643 object->blockType = Type;
645 TRACE("Updating changed flags appropriate for type %d\n", Type);
647 if (Type == WINED3DSBT_ALL) {
649 TRACE("ALL => Pretend everything has changed\n");
650 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
652 /* Lights are not part of the changed / set structure */
653 for(j = 0; j < LIGHTMAP_SIZE; j++) {
655 LIST_FOR_EACH(e, &object->lightMap[j]) {
656 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
657 light->changed = TRUE;
658 light->enabledChanged = TRUE;
661 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
662 object->contained_render_states[j - 1] = j;
664 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
665 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
666 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
667 object->contained_transform_states[j - 1] = j;
669 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
670 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
671 object->contained_vs_consts_f[j] = j;
673 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
674 for(j = 0; j < MAX_CONST_I; j++) {
675 object->contained_vs_consts_i[j] = j;
677 object->num_contained_vs_consts_i = MAX_CONST_I;
678 for(j = 0; j < MAX_CONST_B; j++) {
679 object->contained_vs_consts_b[j] = j;
681 object->num_contained_vs_consts_b = MAX_CONST_B;
682 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
683 object->contained_ps_consts_f[j] = j;
685 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
686 for(j = 0; j < MAX_CONST_I; j++) {
687 object->contained_ps_consts_i[j] = j;
689 object->num_contained_ps_consts_i = MAX_CONST_I;
690 for(j = 0; j < MAX_CONST_B; j++) {
691 object->contained_ps_consts_b[j] = j;
693 object->num_contained_ps_consts_b = MAX_CONST_B;
694 for(i = 0; i < MAX_TEXTURES; i++) {
695 for (j = 0; j <= WINED3D_HIGHEST_TEXTURE_STATE; ++j)
697 object->contained_tss_states[object->num_contained_tss_states].stage = i;
698 object->contained_tss_states[object->num_contained_tss_states].state = j;
699 object->num_contained_tss_states++;
702 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
703 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
704 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
705 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
706 object->num_contained_sampler_states++;
710 for(i = 0; i < MAX_STREAMS; i++) {
711 if(object->streamSource[i]) {
712 IWineD3DBuffer_AddRef(object->streamSource[i]);
715 if(object->pIndexData) {
716 IWineD3DBuffer_AddRef(object->pIndexData);
718 if(object->vertexShader) {
719 IWineD3DVertexShader_AddRef(object->vertexShader);
721 if(object->pixelShader) {
722 IWineD3DPixelShader_AddRef(object->pixelShader);
725 } else if (Type == WINED3DSBT_PIXELSTATE) {
727 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
728 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
730 object->changed.pixelShader = TRUE;
732 /* Pixel Shader Constants */
733 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
734 object->contained_ps_consts_f[i] = i;
735 object->changed.pixelShaderConstantsF[i] = TRUE;
737 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
738 for (i = 0; i < MAX_CONST_B; ++i) {
739 object->contained_ps_consts_b[i] = i;
740 object->changed.pixelShaderConstantsB |= (1 << i);
742 object->num_contained_ps_consts_b = MAX_CONST_B;
743 for (i = 0; i < MAX_CONST_I; ++i) {
744 object->contained_ps_consts_i[i] = i;
745 object->changed.pixelShaderConstantsI |= (1 << i);
747 object->num_contained_ps_consts_i = MAX_CONST_I;
749 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
750 DWORD rs = SavedPixelStates_R[i];
751 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
752 object->contained_render_states[i] = rs;
754 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
755 for (j = 0; j < MAX_TEXTURES; j++) {
756 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
757 DWORD state = SavedPixelStates_T[i];
758 object->changed.textureState[j] |= 1 << state;
759 object->contained_tss_states[object->num_contained_tss_states].stage = j;
760 object->contained_tss_states[object->num_contained_tss_states].state = state;
761 object->num_contained_tss_states++;
764 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
765 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
766 DWORD state = SavedPixelStates_S[i];
767 object->changed.samplerState[j] |= 1 << state;
768 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
769 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
770 object->num_contained_sampler_states++;
773 if(object->pixelShader) {
774 IWineD3DPixelShader_AddRef(object->pixelShader);
777 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
778 * on them. This makes releasing the buffer easier
780 for(i = 0; i < MAX_STREAMS; i++) {
781 object->streamSource[i] = NULL;
783 object->pIndexData = NULL;
784 object->vertexShader = NULL;
786 } else if (Type == WINED3DSBT_VERTEXSTATE) {
788 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
789 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
791 object->changed.vertexShader = TRUE;
793 /* Vertex Shader Constants */
794 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
795 object->changed.vertexShaderConstantsF[i] = TRUE;
796 object->contained_vs_consts_f[i] = i;
798 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
799 for (i = 0; i < MAX_CONST_B; ++i) {
800 object->contained_vs_consts_b[i] = i;
801 object->changed.vertexShaderConstantsB |= (1 << i);
803 object->num_contained_vs_consts_b = MAX_CONST_B;
804 for (i = 0; i < MAX_CONST_I; ++i) {
805 object->contained_vs_consts_i[i] = i;
806 object->changed.vertexShaderConstantsI |= (1 << i);
808 object->num_contained_vs_consts_i = MAX_CONST_I;
809 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
810 DWORD rs = SavedVertexStates_R[i];
811 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
812 object->contained_render_states[i] = rs;
814 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
815 for (j = 0; j < MAX_TEXTURES; j++) {
816 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
817 DWORD state = SavedVertexStates_T[i];
818 object->changed.textureState[j] |= 1 << state;
819 object->contained_tss_states[object->num_contained_tss_states].stage = j;
820 object->contained_tss_states[object->num_contained_tss_states].state = state;
821 object->num_contained_tss_states++;
824 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
825 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
826 DWORD state = SavedVertexStates_S[i];
827 object->changed.samplerState[j] |= 1 << state;
828 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
829 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
830 object->num_contained_sampler_states++;
834 for(j = 0; j < LIGHTMAP_SIZE; j++) {
836 LIST_FOR_EACH(e, &object->lightMap[j]) {
837 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
838 light->changed = TRUE;
839 light->enabledChanged = TRUE;
843 for(i = 0; i < MAX_STREAMS; i++) {
844 if(object->streamSource[i]) {
845 IWineD3DBuffer_AddRef(object->streamSource[i]);
848 if(object->vertexShader) {
849 IWineD3DVertexShader_AddRef(object->vertexShader);
851 object->pIndexData = NULL;
852 object->pixelShader = NULL;
854 FIXME("Unrecognized state block type %d\n", Type);
857 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
861 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
862 WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,
863 DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
864 WINED3DSURFTYPE Impl, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
866 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
867 IWineD3DSurfaceImpl *object;
870 TRACE("(%p) Create surface\n",This);
872 if (Impl == SURFACE_OPENGL && !This->adapter)
874 ERR("OpenGL surfaces are not available without OpenGL.\n");
875 return WINED3DERR_NOTAVAILABLE;
878 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
881 ERR("Failed to allocate surface memory.\n");
883 return WINED3DERR_OUTOFVIDEOMEMORY;
886 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
887 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
890 WARN("Failed to initialize surface, returning %#x.\n", hr);
891 HeapFree(GetProcessHeap(), 0, object);
896 TRACE("(%p) : Created surface %p\n", This, object);
898 *ppSurface = (IWineD3DSurface *)object;
903 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
904 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
906 struct wined3d_rendertarget_view *object;
908 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
911 ERR("Failed to allocate memory\n");
912 return E_OUTOFMEMORY;
915 object->vtbl = &wined3d_rendertarget_view_vtbl;
916 object->refcount = 1;
917 IWineD3DResource_AddRef(resource);
918 object->resource = resource;
919 object->parent = parent;
921 *rendertarget_view = (IWineD3DRendertargetView *)object;
926 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
927 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
928 IWineD3DTexture **ppTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
930 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
931 IWineD3DTextureImpl *object;
934 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
935 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
936 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
938 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
941 ERR("Out of memory\n");
943 return WINED3DERR_OUTOFVIDEOMEMORY;
946 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
949 WARN("Failed to initialize texture, returning %#x\n", hr);
950 HeapFree(GetProcessHeap(), 0, object);
955 *ppTexture = (IWineD3DTexture *)object;
957 TRACE("(%p) : Created texture %p\n", This, object);
962 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
963 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
964 IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
966 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
967 IWineD3DVolumeTextureImpl *object;
970 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
971 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
973 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
976 ERR("Out of memory\n");
977 *ppVolumeTexture = NULL;
978 return WINED3DERR_OUTOFVIDEOMEMORY;
981 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
984 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
985 HeapFree(GetProcessHeap(), 0, object);
986 *ppVolumeTexture = NULL;
990 TRACE("(%p) : Created volume texture %p.\n", This, object);
991 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
996 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
997 UINT Depth, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DVolume **ppVolume,
998 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
1000 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1001 IWineD3DVolumeImpl *object;
1004 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1005 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1007 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1010 ERR("Out of memory\n");
1012 return WINED3DERR_OUTOFVIDEOMEMORY;
1015 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
1018 WARN("Failed to initialize volume, returning %#x.\n", hr);
1019 HeapFree(GetProcessHeap(), 0, object);
1023 TRACE("(%p) : Created volume %p.\n", This, object);
1024 *ppVolume = (IWineD3DVolume *)object;
1029 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
1030 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture,
1031 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
1033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1034 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1037 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1040 ERR("Out of memory\n");
1041 *ppCubeTexture = NULL;
1042 return WINED3DERR_OUTOFVIDEOMEMORY;
1045 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
1048 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1049 HeapFree(GetProcessHeap(), 0, object);
1050 *ppCubeTexture = NULL;
1054 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1055 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1060 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1061 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1062 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1063 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1064 const IWineD3DQueryVtbl *vtable;
1066 /* Just a check to see if we support this type of query */
1068 case WINED3DQUERYTYPE_OCCLUSION:
1069 TRACE("(%p) occlusion query\n", This);
1070 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1073 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1075 vtable = &IWineD3DOcclusionQuery_Vtbl;
1078 case WINED3DQUERYTYPE_EVENT:
1079 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1080 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1081 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1083 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1085 vtable = &IWineD3DEventQuery_Vtbl;
1089 case WINED3DQUERYTYPE_VCACHE:
1090 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1091 case WINED3DQUERYTYPE_VERTEXSTATS:
1092 case WINED3DQUERYTYPE_TIMESTAMP:
1093 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1094 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1095 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1096 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1097 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1098 case WINED3DQUERYTYPE_PIXELTIMINGS:
1099 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1100 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1102 /* Use the base Query vtable until we have a special one for each query */
1103 vtable = &IWineD3DQuery_Vtbl;
1104 FIXME("(%p) Unhandled query type %d\n", This, Type);
1106 if(NULL == ppQuery || hr != WINED3D_OK) {
1110 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1113 ERR("Out of memory\n");
1115 return WINED3DERR_OUTOFVIDEOMEMORY;
1118 object->lpVtbl = vtable;
1119 object->type = Type;
1120 object->state = QUERY_CREATED;
1121 object->wineD3DDevice = This;
1122 object->parent = parent;
1125 *ppQuery = (IWineD3DQuery *)object;
1127 /* allocated the 'extended' data based on the type of query requested */
1129 case WINED3DQUERYTYPE_OCCLUSION:
1130 object->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_occlusion_query));
1131 ((struct wined3d_occlusion_query *)object->extendedData)->context = NULL;
1134 case WINED3DQUERYTYPE_EVENT:
1135 object->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_event_query));
1136 ((struct wined3d_event_query *)object->extendedData)->context = NULL;
1139 case WINED3DQUERYTYPE_VCACHE:
1140 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1141 case WINED3DQUERYTYPE_VERTEXSTATS:
1142 case WINED3DQUERYTYPE_TIMESTAMP:
1143 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1144 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1145 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1146 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1147 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1148 case WINED3DQUERYTYPE_PIXELTIMINGS:
1149 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1150 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1152 object->extendedData = 0;
1153 FIXME("(%p) Unhandled query type %d\n",This , Type);
1155 TRACE("(%p) : Created Query %p\n", This, object);
1159 /*****************************************************************************
1160 * IWineD3DDeviceImpl_SetupFullscreenWindow
1162 * Helper function that modifies a HWND's Style and ExStyle for proper
1166 * iface: Pointer to the IWineD3DDevice interface
1167 * window: Window to setup
1169 *****************************************************************************/
1170 static LONG fullscreen_style(LONG orig_style) {
1171 LONG style = orig_style;
1172 style &= ~WS_CAPTION;
1173 style &= ~WS_THICKFRAME;
1175 /* Make sure the window is managed, otherwise we won't get keyboard input */
1176 style |= WS_POPUP | WS_SYSMENU;
1181 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1182 LONG exStyle = orig_exStyle;
1184 /* Filter out window decorations */
1185 exStyle &= ~WS_EX_WINDOWEDGE;
1186 exStyle &= ~WS_EX_CLIENTEDGE;
1191 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1194 LONG style, exStyle;
1195 /* Don't do anything if an original style is stored.
1196 * That shouldn't happen
1198 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1199 if (This->style || This->exStyle) {
1200 ERR("(%p): Want to change the window parameters of HWND %p, but "
1201 "another style is stored for restoration afterwards\n", This, window);
1204 /* Get the parameters and save them */
1205 style = GetWindowLongW(window, GWL_STYLE);
1206 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1207 This->style = style;
1208 This->exStyle = exStyle;
1210 style = fullscreen_style(style);
1211 exStyle = fullscreen_exStyle(exStyle);
1213 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1214 This->style, This->exStyle, style, exStyle);
1216 SetWindowLongW(window, GWL_STYLE, style);
1217 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1219 /* Inform the window about the update. */
1220 SetWindowPos(window, HWND_TOP, 0, 0,
1221 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1224 /*****************************************************************************
1225 * IWineD3DDeviceImpl_RestoreWindow
1227 * Helper function that restores a windows' properties when taking it out
1228 * of fullscreen mode
1231 * iface: Pointer to the IWineD3DDevice interface
1232 * window: Window to setup
1234 *****************************************************************************/
1235 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1236 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1237 LONG style, exStyle;
1239 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1240 * switch, do nothing
1242 if (!This->style && !This->exStyle) return;
1244 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1245 This, window, This->style, This->exStyle);
1247 style = GetWindowLongW(window, GWL_STYLE);
1248 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1250 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1251 * Some applications change it before calling Reset() when switching between windowed and
1252 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1254 if(style == fullscreen_style(This->style) &&
1255 exStyle == fullscreen_style(This->exStyle)) {
1256 SetWindowLongW(window, GWL_STYLE, This->style);
1257 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1260 /* Delete the old values */
1264 /* Inform the window about the update */
1265 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1266 0, 0, 0, 0, /* Pos, Size, ignored */
1267 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1270 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1271 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1272 WINED3DPRESENT_PARAMETERS *pPresentationParameters, IWineD3DSwapChain **ppSwapChain,
1273 IUnknown *parent, WINED3DSURFTYPE surface_type)
1275 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1278 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1280 BOOL displaymode_set = FALSE;
1281 WINED3DDISPLAYMODE Mode;
1282 const struct GlPixelFormatDesc *format_desc;
1284 TRACE("(%p) : Created Additional Swap Chain\n", This);
1286 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1287 * does a device hold a reference to a swap chain giving them a lifetime of the device
1288 * or does the swap chain notify the device of its destruction.
1289 *******************************/
1291 /* Check the params */
1292 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1293 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1294 return WINED3DERR_INVALIDCALL;
1295 } else if (pPresentationParameters->BackBufferCount > 1) {
1296 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");
1299 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1302 ERR("Out of memory\n");
1303 *ppSwapChain = NULL;
1304 return WINED3DERR_OUTOFVIDEOMEMORY;
1307 switch(surface_type) {
1309 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1311 case SURFACE_OPENGL:
1312 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1314 case SURFACE_UNKNOWN:
1315 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1316 HeapFree(GetProcessHeap(), 0, object);
1317 return WINED3DERR_INVALIDCALL;
1319 object->wineD3DDevice = This;
1320 object->parent = parent;
1323 *ppSwapChain = (IWineD3DSwapChain *)object;
1325 /*********************
1326 * Lookup the window Handle and the relating X window handle
1327 ********************/
1329 /* Setup hwnd we are using, plus which display this equates to */
1330 object->win_handle = pPresentationParameters->hDeviceWindow;
1331 if (!object->win_handle) {
1332 object->win_handle = This->createParms.hFocusWindow;
1334 if(!pPresentationParameters->Windowed && object->win_handle) {
1335 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1336 pPresentationParameters->BackBufferWidth,
1337 pPresentationParameters->BackBufferHeight);
1340 hDc = GetDC(object->win_handle);
1341 TRACE("Using hDc %p\n", hDc);
1344 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1345 return WINED3DERR_NOTAVAILABLE;
1348 /* Get info on the current display setup */
1349 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1350 object->orig_width = Mode.Width;
1351 object->orig_height = Mode.Height;
1352 object->orig_fmt = Mode.Format;
1353 format_desc = getFormatDescEntry(Mode.Format, &GLINFO_LOCATION);
1355 if (pPresentationParameters->Windowed &&
1356 ((pPresentationParameters->BackBufferWidth == 0) ||
1357 (pPresentationParameters->BackBufferHeight == 0) ||
1358 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1361 GetClientRect(object->win_handle, &Rect);
1363 if (pPresentationParameters->BackBufferWidth == 0) {
1364 pPresentationParameters->BackBufferWidth = Rect.right;
1365 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1367 if (pPresentationParameters->BackBufferHeight == 0) {
1368 pPresentationParameters->BackBufferHeight = Rect.bottom;
1369 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1371 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1372 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1373 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1377 /* Put the correct figures in the presentation parameters */
1378 TRACE("Copying across presentation parameters\n");
1379 object->presentParms = *pPresentationParameters;
1381 TRACE("calling rendertarget CB\n");
1382 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1383 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1384 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1385 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->frontBuffer);
1386 if (SUCCEEDED(hr)) {
1387 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1388 ((IWineD3DSurfaceImpl *)object->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
1389 if(surface_type == SURFACE_OPENGL) {
1390 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1393 ERR("Failed to create the front buffer\n");
1397 /*********************
1398 * Windowed / Fullscreen
1399 *******************/
1402 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1403 * so we should really check to see if there is a fullscreen swapchain already
1404 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1405 **************************************/
1407 if (!pPresentationParameters->Windowed) {
1408 WINED3DDISPLAYMODE mode;
1411 /* Change the display settings */
1412 mode.Width = pPresentationParameters->BackBufferWidth;
1413 mode.Height = pPresentationParameters->BackBufferHeight;
1414 mode.Format = pPresentationParameters->BackBufferFormat;
1415 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1417 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1418 displaymode_set = TRUE;
1422 * Create an opengl context for the display visual
1423 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1424 * use different properties after that point in time. FIXME: How to handle when requested format
1425 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1426 * it chooses is identical to the one already being used!
1427 **********************************/
1428 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1430 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1431 if(!object->context) {
1432 ERR("Failed to create the context array\n");
1436 object->num_contexts = 1;
1438 if(surface_type == SURFACE_OPENGL) {
1439 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1440 if (!object->context[0]) {
1441 ERR("Failed to create a new context\n");
1442 hr = WINED3DERR_NOTAVAILABLE;
1445 TRACE("Context created (HWND=%p, glContext=%p)\n",
1446 object->win_handle, object->context[0]->glCtx);
1450 /*********************
1451 * Create the back, front and stencil buffers
1452 *******************/
1453 if(object->presentParms.BackBufferCount > 0) {
1456 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1457 if(!object->backBuffer) {
1458 ERR("Out of memory\n");
1463 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1464 TRACE("calling rendertarget CB\n");
1465 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1466 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1467 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1468 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->backBuffer[i]);
1470 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1471 ((IWineD3DSurfaceImpl *)object->backBuffer[i])->Flags |= SFLAG_SWAPCHAIN;
1473 ERR("Cannot create new back buffer\n");
1476 if(surface_type == SURFACE_OPENGL) {
1478 glDrawBuffer(GL_BACK);
1479 checkGLcall("glDrawBuffer(GL_BACK)");
1484 object->backBuffer = NULL;
1486 /* Single buffering - draw to front buffer */
1487 if(surface_type == SURFACE_OPENGL) {
1489 glDrawBuffer(GL_FRONT);
1490 checkGLcall("glDrawBuffer(GL_FRONT)");
1495 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1496 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1497 TRACE("Creating depth stencil buffer\n");
1498 if (This->auto_depth_stencil_buffer == NULL ) {
1499 hr = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent, parent,
1500 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1501 object->presentParms.AutoDepthStencilFormat, object->presentParms.MultiSampleType,
1502 object->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */,
1503 &This->auto_depth_stencil_buffer);
1504 if (SUCCEEDED(hr)) {
1505 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1507 ERR("Failed to create the auto depth stencil\n");
1513 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1515 TRACE("Created swapchain %p\n", object);
1516 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1520 if (displaymode_set) {
1524 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1527 /* Change the display settings */
1528 memset(&devmode, 0, sizeof(devmode));
1529 devmode.dmSize = sizeof(devmode);
1530 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1531 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1532 devmode.dmPelsWidth = object->orig_width;
1533 devmode.dmPelsHeight = object->orig_height;
1534 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1537 if (object->backBuffer) {
1539 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1540 if (object->backBuffer[i]) IWineD3DSurface_Release(object->backBuffer[i]);
1542 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1543 object->backBuffer = NULL;
1545 if(object->context && object->context[0])
1546 DestroyContext(This, object->context[0]);
1547 if (object->frontBuffer) IWineD3DSurface_Release(object->frontBuffer);
1548 HeapFree(GetProcessHeap(), 0, object);
1552 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1553 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1554 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1555 TRACE("(%p)\n", This);
1557 return This->NumberOfSwapChains;
1560 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1561 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1562 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1564 if(iSwapChain < This->NumberOfSwapChains) {
1565 *pSwapChain = This->swapchains[iSwapChain];
1566 IWineD3DSwapChain_AddRef(*pSwapChain);
1567 TRACE("(%p) returning %p\n", This, *pSwapChain);
1570 TRACE("Swapchain out of range\n");
1572 return WINED3DERR_INVALIDCALL;
1576 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1577 IWineD3DVertexDeclaration **declaration, IUnknown *parent, const struct wined3d_parent_ops *parent_ops,
1578 const WINED3DVERTEXELEMENT *elements, UINT element_count)
1580 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1581 IWineD3DVertexDeclarationImpl *object = NULL;
1584 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1585 iface, declaration, parent, elements, element_count);
1587 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1590 ERR("Failed to allocate vertex declaration memory.\n");
1591 return E_OUTOFMEMORY;
1594 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1597 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1598 HeapFree(GetProcessHeap(), 0, object);
1602 TRACE("Created verrtex declaration %p.\n", object);
1603 *declaration = (IWineD3DVertexDeclaration *)object;
1608 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1609 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1611 unsigned int idx, idx2;
1612 unsigned int offset;
1613 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1614 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1615 BOOL has_blend_idx = has_blend &&
1616 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1617 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1618 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1619 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1620 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1621 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1622 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1624 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1625 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1626 WINED3DVERTEXELEMENT *elements = NULL;
1629 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1630 if (has_blend_idx) num_blends--;
1632 /* Compute declaration size */
1633 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1634 has_psize + has_diffuse + has_specular + num_textures;
1636 /* convert the declaration */
1637 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1638 if (!elements) return ~0U;
1642 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1643 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1644 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
1646 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1647 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1648 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1651 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1652 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1654 elements[idx].usage_idx = 0;
1657 if (has_blend && (num_blends > 0)) {
1658 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1659 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1661 switch(num_blends) {
1662 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
1663 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
1664 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
1665 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
1667 ERR("Unexpected amount of blend values: %u\n", num_blends);
1670 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1671 elements[idx].usage_idx = 0;
1674 if (has_blend_idx) {
1675 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1676 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1677 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
1678 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1679 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1681 elements[idx].format = WINED3DFMT_R32_FLOAT;
1682 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
1683 elements[idx].usage_idx = 0;
1687 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1688 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
1689 elements[idx].usage_idx = 0;
1693 elements[idx].format = WINED3DFMT_R32_FLOAT;
1694 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
1695 elements[idx].usage_idx = 0;
1699 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1700 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1701 elements[idx].usage_idx = 0;
1705 elements[idx].format = WINED3DFMT_B8G8R8A8_UNORM;
1706 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1707 elements[idx].usage_idx = 1;
1710 for (idx2 = 0; idx2 < num_textures; idx2++) {
1711 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1712 switch (numcoords) {
1713 case WINED3DFVF_TEXTUREFORMAT1:
1714 elements[idx].format = WINED3DFMT_R32_FLOAT;
1716 case WINED3DFVF_TEXTUREFORMAT2:
1717 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
1719 case WINED3DFVF_TEXTUREFORMAT3:
1720 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1722 case WINED3DFVF_TEXTUREFORMAT4:
1723 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1726 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
1727 elements[idx].usage_idx = idx2;
1731 /* Now compute offsets, and initialize the rest of the fields */
1732 for (idx = 0, offset = 0; idx < size; ++idx)
1734 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
1735 elements[idx].input_slot = 0;
1736 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1737 elements[idx].offset = offset;
1738 offset += format_desc->component_count * format_desc->component_size;
1741 *ppVertexElements = elements;
1745 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1746 IWineD3DVertexDeclaration **declaration, IUnknown *parent,
1747 const struct wined3d_parent_ops *parent_ops, DWORD fvf)
1749 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1750 WINED3DVERTEXELEMENT *elements;
1754 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1756 size = ConvertFvfToDeclaration(This, fvf, &elements);
1757 if (size == ~0U) return E_OUTOFMEMORY;
1759 hr = IWineD3DDevice_CreateVertexDeclaration(iface, declaration, parent, parent_ops, elements, size);
1760 HeapFree(GetProcessHeap(), 0, elements);
1764 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1765 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1766 IWineD3DVertexShader **ppVertexShader, IUnknown *parent,
1767 const struct wined3d_parent_ops *parent_ops)
1769 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1770 IWineD3DVertexShaderImpl *object;
1773 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1776 ERR("Failed to allocate shader memory.\n");
1777 return E_OUTOFMEMORY;
1780 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1783 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1784 HeapFree(GetProcessHeap(), 0, object);
1788 TRACE("Created vertex shader %p.\n", object);
1789 *ppVertexShader = (IWineD3DVertexShader *)object;
1794 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1795 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1796 IWineD3DPixelShader **ppPixelShader, IUnknown *parent,
1797 const struct wined3d_parent_ops *parent_ops)
1799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1800 IWineD3DPixelShaderImpl *object;
1803 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1806 ERR("Failed to allocate shader memory.\n");
1807 return E_OUTOFMEMORY;
1810 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1813 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1814 HeapFree(GetProcessHeap(), 0, object);
1818 TRACE("Created pixel shader %p.\n", object);
1819 *ppPixelShader = (IWineD3DPixelShader *)object;
1824 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1825 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1827 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1828 IWineD3DPaletteImpl *object;
1830 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1832 /* Create the new object */
1833 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1835 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1836 return E_OUTOFMEMORY;
1839 object->lpVtbl = &IWineD3DPalette_Vtbl;
1841 object->Flags = Flags;
1842 object->parent = Parent;
1843 object->wineD3DDevice = This;
1844 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1845 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1848 HeapFree( GetProcessHeap(), 0, object);
1849 return E_OUTOFMEMORY;
1852 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1854 IWineD3DPalette_Release((IWineD3DPalette *) object);
1858 *Palette = (IWineD3DPalette *) object;
1863 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1867 HDC dcb = NULL, dcs = NULL;
1868 WINEDDCOLORKEY colorkey;
1870 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1873 GetObjectA(hbm, sizeof(BITMAP), &bm);
1874 dcb = CreateCompatibleDC(NULL);
1876 SelectObject(dcb, hbm);
1880 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1881 * couldn't be loaded
1883 memset(&bm, 0, sizeof(bm));
1888 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1889 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1890 NULL, &wined3d_null_parent_ops);
1892 ERR("Wine logo requested, but failed to create surface\n");
1897 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1898 if(FAILED(hr)) goto out;
1899 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1900 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1902 colorkey.dwColorSpaceLowValue = 0;
1903 colorkey.dwColorSpaceHighValue = 0;
1904 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1906 /* Fill the surface with a white color to show that wined3d is there */
1907 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1920 /* Context activation is done by the caller. */
1921 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
1923 /* Under DirectX you can have texture stage operations even if no texture is
1924 bound, whereas opengl will only do texture operations when a valid texture is
1925 bound. We emulate this by creating dummy textures and binding them to each
1926 texture stage, but disable all stages by default. Hence if a stage is enabled
1927 then the default texture will kick in until replaced by a SetTexture call */
1930 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
1931 /* The dummy texture does not have client storage backing */
1932 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1933 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1935 for (i = 0; i < GL_LIMITS(textures); i++) {
1936 GLubyte white = 255;
1938 /* Make appropriate texture active */
1939 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1940 checkGLcall("glActiveTextureARB");
1942 /* Generate an opengl texture name */
1943 glGenTextures(1, &This->dummyTextureName[i]);
1944 checkGLcall("glGenTextures");
1945 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1947 /* Generate a dummy 2d texture (not using 1d because they cause many
1948 * DRI drivers fall back to sw) */
1949 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1950 checkGLcall("glBindTexture");
1952 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1953 checkGLcall("glTexImage2D");
1955 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
1956 /* Reenable because if supported it is enabled by default */
1957 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1958 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1964 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1965 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1967 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1968 IWineD3DSwapChainImpl *swapchain = NULL;
1973 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1975 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1976 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1978 /* TODO: Test if OpenGL is compiled in and loaded */
1980 TRACE("(%p) : Creating stateblock\n", This);
1981 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1982 hr = IWineD3DDevice_CreateStateBlock(iface,
1984 (IWineD3DStateBlock **)&This->stateBlock,
1986 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1987 WARN("Failed to create stateblock\n");
1990 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1991 This->updateStateBlock = This->stateBlock;
1992 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1994 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1995 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
1997 This->NumberOfPalettes = 1;
1998 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1999 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2000 ERR("Out of memory!\n");
2003 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2004 if(!This->palettes[0]) {
2005 ERR("Out of memory!\n");
2008 for (i = 0; i < 256; ++i) {
2009 This->palettes[0][i].peRed = 0xFF;
2010 This->palettes[0][i].peGreen = 0xFF;
2011 This->palettes[0][i].peBlue = 0xFF;
2012 This->palettes[0][i].peFlags = 0xFF;
2014 This->currentPalette = 0;
2016 /* Initialize the texture unit mapping to a 1:1 mapping */
2017 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2018 if (state < GL_LIMITS(fragment_samplers)) {
2019 This->texUnitMap[state] = state;
2020 This->rev_tex_unit_map[state] = state;
2022 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
2023 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
2027 /* Setup the implicit swapchain. This also initializes a context. */
2028 TRACE("Creating implicit swapchain\n");
2029 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2030 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2033 WARN("Failed to create implicit swapchain\n");
2037 This->NumberOfSwapChains = 1;
2038 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2039 if(!This->swapchains) {
2040 ERR("Out of memory!\n");
2043 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2045 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2046 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2047 This->render_targets[0] = swapchain->backBuffer[0];
2050 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2051 This->render_targets[0] = swapchain->frontBuffer;
2053 IWineD3DSurface_AddRef(This->render_targets[0]);
2055 /* Depth Stencil support */
2056 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2057 if (NULL != This->stencilBufferTarget) {
2058 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2061 hr = This->shader_backend->shader_alloc_private(iface);
2063 TRACE("Shader private data couldn't be allocated\n");
2066 hr = This->frag_pipe->alloc_private(iface);
2068 TRACE("Fragment pipeline private data couldn't be allocated\n");
2071 hr = This->blitter->alloc_private(iface);
2073 TRACE("Blitter private data couldn't be allocated\n");
2077 /* Set up some starting GL setup */
2079 /* Setup all the devices defaults */
2080 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2081 create_dummy_textures(This);
2085 /* Initialize the current view state */
2086 This->view_ident = 1;
2087 This->contexts[0]->last_was_rhw = 0;
2088 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2089 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2091 switch(wined3d_settings.offscreen_rendering_mode) {
2094 This->offscreenBuffer = GL_BACK;
2097 case ORM_BACKBUFFER:
2099 if (context_get_current()->aux_buffers > 0)
2101 TRACE("Using auxilliary buffer for offscreen rendering\n");
2102 This->offscreenBuffer = GL_AUX0;
2104 TRACE("Using back buffer for offscreen rendering\n");
2105 This->offscreenBuffer = GL_BACK;
2110 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2113 /* Clear the screen */
2114 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2115 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2118 This->d3d_initialized = TRUE;
2120 if(wined3d_settings.logo) {
2121 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2123 This->highest_dirty_ps_const = 0;
2124 This->highest_dirty_vs_const = 0;
2128 HeapFree(GetProcessHeap(), 0, This->render_targets);
2129 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2130 HeapFree(GetProcessHeap(), 0, This->swapchains);
2131 This->NumberOfSwapChains = 0;
2132 if(This->palettes) {
2133 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2134 HeapFree(GetProcessHeap(), 0, This->palettes);
2136 This->NumberOfPalettes = 0;
2138 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2140 if(This->stateBlock) {
2141 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2142 This->stateBlock = NULL;
2144 if (This->blit_priv) {
2145 This->blitter->free_private(iface);
2147 if (This->fragment_priv) {
2148 This->frag_pipe->free_private(iface);
2150 if (This->shader_priv) {
2151 This->shader_backend->shader_free_private(iface);
2156 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2157 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2160 IWineD3DSwapChainImpl *swapchain = NULL;
2163 /* Setup the implicit swapchain */
2164 TRACE("Creating implicit swapchain\n");
2165 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2166 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2169 WARN("Failed to create implicit swapchain\n");
2173 This->NumberOfSwapChains = 1;
2174 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2175 if(!This->swapchains) {
2176 ERR("Out of memory!\n");
2179 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2183 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2187 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2189 IWineD3DResource_UnLoad(resource);
2190 IWineD3DResource_Release(resource);
2194 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
2195 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
2197 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2198 const struct wined3d_context *context;
2199 const struct wined3d_gl_info *gl_info;
2202 TRACE("(%p)\n", This);
2204 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2206 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2207 * it was created. Thus make sure a context is active for the glDelete* calls
2209 context = ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
2210 gl_info = context->gl_info;
2212 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2214 /* Unload resources */
2215 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2217 TRACE("Deleting high order patches\n");
2218 for(i = 0; i < PATCHMAP_SIZE; i++) {
2219 struct list *e1, *e2;
2220 struct WineD3DRectPatch *patch;
2221 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2222 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2223 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2227 /* Delete the palette conversion shader if it is around */
2228 if(This->paletteConversionShader) {
2230 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2232 This->paletteConversionShader = 0;
2235 /* Delete the pbuffer context if there is any */
2236 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2238 /* Delete the mouse cursor texture */
2239 if(This->cursorTexture) {
2241 glDeleteTextures(1, &This->cursorTexture);
2243 This->cursorTexture = 0;
2246 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2247 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2249 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2250 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2253 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2254 * private data, it might contain opengl pointers
2256 if(This->depth_blt_texture) {
2258 glDeleteTextures(1, &This->depth_blt_texture);
2260 This->depth_blt_texture = 0;
2262 if (This->depth_blt_rb) {
2264 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2266 This->depth_blt_rb = 0;
2267 This->depth_blt_rb_w = 0;
2268 This->depth_blt_rb_h = 0;
2271 /* Release the update stateblock */
2272 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2273 if(This->updateStateBlock != This->stateBlock)
2274 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2276 This->updateStateBlock = NULL;
2278 { /* because were not doing proper internal refcounts releasing the primary state block
2279 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2280 to set this->stateBlock = NULL; first */
2281 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2282 This->stateBlock = NULL;
2284 /* Release the stateblock */
2285 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2286 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2290 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2291 This->blitter->free_private(iface);
2292 This->frag_pipe->free_private(iface);
2293 This->shader_backend->shader_free_private(iface);
2295 /* Release the buffers (with sanity checks)*/
2296 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2297 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2298 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2299 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2301 This->stencilBufferTarget = NULL;
2303 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2304 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2305 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2307 TRACE("Setting rendertarget to NULL\n");
2308 This->render_targets[0] = NULL;
2310 if (This->auto_depth_stencil_buffer) {
2311 if (IWineD3DSurface_Release(This->auto_depth_stencil_buffer) > 0)
2313 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2315 This->auto_depth_stencil_buffer = NULL;
2318 for(i=0; i < This->NumberOfSwapChains; i++) {
2319 TRACE("Releasing the implicit swapchain %d\n", i);
2320 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2321 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2325 HeapFree(GetProcessHeap(), 0, This->swapchains);
2326 This->swapchains = NULL;
2327 This->NumberOfSwapChains = 0;
2329 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2330 HeapFree(GetProcessHeap(), 0, This->palettes);
2331 This->palettes = NULL;
2332 This->NumberOfPalettes = 0;
2334 HeapFree(GetProcessHeap(), 0, This->render_targets);
2335 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2336 This->render_targets = NULL;
2337 This->draw_buffers = NULL;
2339 This->d3d_initialized = FALSE;
2343 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2347 for(i=0; i < This->NumberOfSwapChains; i++) {
2348 TRACE("Releasing the implicit swapchain %d\n", i);
2349 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2350 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2354 HeapFree(GetProcessHeap(), 0, This->swapchains);
2355 This->swapchains = NULL;
2356 This->NumberOfSwapChains = 0;
2360 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2361 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2362 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2364 * There is no way to deactivate thread safety once it is enabled.
2366 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2367 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2369 /*For now just store the flag(needed in case of ddraw) */
2370 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2375 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2376 const WINED3DDISPLAYMODE* pMode) {
2378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2380 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &GLINFO_LOCATION);
2383 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2385 /* Resize the screen even without a window:
2386 * The app could have unset it with SetCooperativeLevel, but not called
2387 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2388 * but we don't have any hwnd
2391 memset(&devmode, 0, sizeof(devmode));
2392 devmode.dmSize = sizeof(devmode);
2393 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2394 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2395 devmode.dmPelsWidth = pMode->Width;
2396 devmode.dmPelsHeight = pMode->Height;
2398 devmode.dmDisplayFrequency = pMode->RefreshRate;
2399 if (pMode->RefreshRate != 0) {
2400 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2403 /* Only change the mode if necessary */
2404 if( (This->ddraw_width == pMode->Width) &&
2405 (This->ddraw_height == pMode->Height) &&
2406 (This->ddraw_format == pMode->Format) &&
2407 (pMode->RefreshRate == 0) ) {
2411 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2412 if (ret != DISP_CHANGE_SUCCESSFUL) {
2413 if(devmode.dmDisplayFrequency != 0) {
2414 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2415 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2416 devmode.dmDisplayFrequency = 0;
2417 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2419 if(ret != DISP_CHANGE_SUCCESSFUL) {
2420 return WINED3DERR_NOTAVAILABLE;
2424 /* Store the new values */
2425 This->ddraw_width = pMode->Width;
2426 This->ddraw_height = pMode->Height;
2427 This->ddraw_format = pMode->Format;
2429 /* And finally clip mouse to our screen */
2430 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2431 ClipCursor(&clip_rc);
2436 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2437 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2438 *ppD3D= This->wineD3D;
2439 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2440 IWineD3D_AddRef(*ppD3D);
2444 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2445 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2447 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2448 (This->adapter->TextureRam/(1024*1024)),
2449 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2450 /* return simulated texture memory left */
2451 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2455 * Get / Set Stream Source
2457 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2458 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2461 IWineD3DBuffer *oldSrc;
2463 if (StreamNumber >= MAX_STREAMS) {
2464 WARN("Stream out of range %d\n", StreamNumber);
2465 return WINED3DERR_INVALIDCALL;
2466 } else if(OffsetInBytes & 0x3) {
2467 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2468 return WINED3DERR_INVALIDCALL;
2471 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2472 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2474 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2476 if(oldSrc == pStreamData &&
2477 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2478 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2479 TRACE("Application is setting the old values over, nothing to do\n");
2483 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2485 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2486 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2489 /* Handle recording of state blocks */
2490 if (This->isRecordingState) {
2491 TRACE("Recording... not performing anything\n");
2492 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2493 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2497 if (pStreamData != NULL) {
2498 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2499 IWineD3DBuffer_AddRef(pStreamData);
2501 if (oldSrc != NULL) {
2502 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2503 IWineD3DBuffer_Release(oldSrc);
2506 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2511 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2512 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2514 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2516 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2517 This->stateBlock->streamSource[StreamNumber],
2518 This->stateBlock->streamOffset[StreamNumber],
2519 This->stateBlock->streamStride[StreamNumber]);
2521 if (StreamNumber >= MAX_STREAMS) {
2522 WARN("Stream out of range %d\n", StreamNumber);
2523 return WINED3DERR_INVALIDCALL;
2525 *pStream = This->stateBlock->streamSource[StreamNumber];
2526 *pStride = This->stateBlock->streamStride[StreamNumber];
2528 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2531 if (*pStream != NULL) {
2532 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2537 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2538 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2539 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2540 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2542 /* Verify input at least in d3d9 this is invalid*/
2543 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2544 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2545 return WINED3DERR_INVALIDCALL;
2547 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2548 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2549 return WINED3DERR_INVALIDCALL;
2552 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2553 return WINED3DERR_INVALIDCALL;
2556 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2557 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2559 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2560 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2562 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2563 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2564 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2570 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2571 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2573 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2574 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2576 TRACE("(%p) : returning %d\n", This, *Divider);
2582 * Get / Set & Multiply Transform
2584 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2585 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2587 /* Most of this routine, comments included copied from ddraw tree initially: */
2588 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2590 /* Handle recording of state blocks */
2591 if (This->isRecordingState) {
2592 TRACE("Recording... not performing anything\n");
2593 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2594 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2599 * If the new matrix is the same as the current one,
2600 * we cut off any further processing. this seems to be a reasonable
2601 * optimization because as was noticed, some apps (warcraft3 for example)
2602 * tend towards setting the same matrix repeatedly for some reason.
2604 * From here on we assume that the new matrix is different, wherever it matters.
2606 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2607 TRACE("The app is setting the same matrix over again\n");
2610 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2614 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2615 where ViewMat = Camera space, WorldMat = world space.
2617 In OpenGL, camera and world space is combined into GL_MODELVIEW
2618 matrix. The Projection matrix stay projection matrix.
2621 /* Capture the times we can just ignore the change for now */
2622 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2623 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2624 /* Handled by the state manager */
2627 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2631 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2632 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2633 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2634 *pMatrix = This->stateBlock->transforms[State];
2638 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2639 const WINED3DMATRIX *mat = NULL;
2642 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2643 * below means it will be recorded in a state block change, but it
2644 * works regardless where it is recorded.
2645 * If this is found to be wrong, change to StateBlock.
2647 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2648 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2650 if (State <= HIGHEST_TRANSFORMSTATE)
2652 mat = &This->updateStateBlock->transforms[State];
2654 FIXME("Unhandled transform state!!\n");
2657 multiply_matrix(&temp, mat, pMatrix);
2659 /* Apply change via set transform - will reapply to eg. lights this way */
2660 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2666 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2667 you can reference any indexes you want as long as that number max are enabled at any
2668 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2669 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2670 but when recording, just build a chain pretty much of commands to be replayed. */
2672 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2674 PLIGHTINFOEL *object = NULL;
2675 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2678 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2679 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2681 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2685 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2686 return WINED3DERR_INVALIDCALL;
2689 switch(pLight->Type) {
2690 case WINED3DLIGHT_POINT:
2691 case WINED3DLIGHT_SPOT:
2692 case WINED3DLIGHT_PARALLELPOINT:
2693 case WINED3DLIGHT_GLSPOT:
2694 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2697 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2699 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2700 return WINED3DERR_INVALIDCALL;
2704 case WINED3DLIGHT_DIRECTIONAL:
2705 /* Ignores attenuation */
2709 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2710 return WINED3DERR_INVALIDCALL;
2713 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2714 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2715 if(object->OriginalIndex == Index) break;
2720 TRACE("Adding new light\n");
2721 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2723 ERR("Out of memory error when allocating a light\n");
2724 return E_OUTOFMEMORY;
2726 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2727 object->glIndex = -1;
2728 object->OriginalIndex = Index;
2729 object->changed = TRUE;
2732 /* Initialize the object */
2733 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,
2734 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2735 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2736 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2737 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2738 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2739 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2741 /* Save away the information */
2742 object->OriginalParms = *pLight;
2744 switch (pLight->Type) {
2745 case WINED3DLIGHT_POINT:
2747 object->lightPosn[0] = pLight->Position.x;
2748 object->lightPosn[1] = pLight->Position.y;
2749 object->lightPosn[2] = pLight->Position.z;
2750 object->lightPosn[3] = 1.0f;
2751 object->cutoff = 180.0f;
2755 case WINED3DLIGHT_DIRECTIONAL:
2757 object->lightPosn[0] = -pLight->Direction.x;
2758 object->lightPosn[1] = -pLight->Direction.y;
2759 object->lightPosn[2] = -pLight->Direction.z;
2760 object->lightPosn[3] = 0.0f;
2761 object->exponent = 0.0f;
2762 object->cutoff = 180.0f;
2765 case WINED3DLIGHT_SPOT:
2767 object->lightPosn[0] = pLight->Position.x;
2768 object->lightPosn[1] = pLight->Position.y;
2769 object->lightPosn[2] = pLight->Position.z;
2770 object->lightPosn[3] = 1.0f;
2773 object->lightDirn[0] = pLight->Direction.x;
2774 object->lightDirn[1] = pLight->Direction.y;
2775 object->lightDirn[2] = pLight->Direction.z;
2776 object->lightDirn[3] = 1.0f;
2779 * opengl-ish and d3d-ish spot lights use too different models for the
2780 * light "intensity" as a function of the angle towards the main light direction,
2781 * so we only can approximate very roughly.
2782 * however spot lights are rather rarely used in games (if ever used at all).
2783 * furthermore if still used, probably nobody pays attention to such details.
2785 if (pLight->Falloff == 0) {
2786 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2787 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2788 * will always be 1.0 for both of them, and we don't have to care for the
2789 * rest of the rather complex calculation
2791 object->exponent = 0.0f;
2793 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2794 if (rho < 0.0001f) rho = 0.0001f;
2795 object->exponent = -0.3f/logf(cosf(rho/2));
2797 if (object->exponent > 128.0f)
2799 object->exponent = 128.0f;
2801 object->cutoff = pLight->Phi*90/M_PI;
2807 FIXME("Unrecognized light type %d\n", pLight->Type);
2810 /* Update the live definitions if the light is currently assigned a glIndex */
2811 if (object->glIndex != -1 && !This->isRecordingState) {
2812 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2817 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2818 PLIGHTINFOEL *lightInfo = NULL;
2819 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2820 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2822 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2824 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2825 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2826 if(lightInfo->OriginalIndex == Index) break;
2830 if (lightInfo == NULL) {
2831 TRACE("Light information requested but light not defined\n");
2832 return WINED3DERR_INVALIDCALL;
2835 *pLight = lightInfo->OriginalParms;
2840 * Get / Set Light Enable
2841 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2843 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2844 PLIGHTINFOEL *lightInfo = NULL;
2845 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2846 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2848 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2850 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2851 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2852 if(lightInfo->OriginalIndex == Index) break;
2855 TRACE("Found light: %p\n", lightInfo);
2857 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2858 if (lightInfo == NULL) {
2860 TRACE("Light enabled requested but light not defined, so defining one!\n");
2861 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2863 /* Search for it again! Should be fairly quick as near head of list */
2864 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2865 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2866 if(lightInfo->OriginalIndex == Index) break;
2869 if (lightInfo == NULL) {
2870 FIXME("Adding default lights has failed dismally\n");
2871 return WINED3DERR_INVALIDCALL;
2875 lightInfo->enabledChanged = TRUE;
2877 if(lightInfo->glIndex != -1) {
2878 if(!This->isRecordingState) {
2879 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2882 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2883 lightInfo->glIndex = -1;
2885 TRACE("Light already disabled, nothing to do\n");
2887 lightInfo->enabled = FALSE;
2889 lightInfo->enabled = TRUE;
2890 if (lightInfo->glIndex != -1) {
2892 TRACE("Nothing to do as light was enabled\n");
2895 /* Find a free gl light */
2896 for(i = 0; i < This->maxConcurrentLights; i++) {
2897 if(This->updateStateBlock->activeLights[i] == NULL) {
2898 This->updateStateBlock->activeLights[i] = lightInfo;
2899 lightInfo->glIndex = i;
2903 if(lightInfo->glIndex == -1) {
2904 /* Our tests show that Windows returns D3D_OK in this situation, even with
2905 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2906 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2907 * as well for those lights.
2909 * TODO: Test how this affects rendering
2911 WARN("Too many concurrently active lights\n");
2915 /* i == lightInfo->glIndex */
2916 if(!This->isRecordingState) {
2917 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2925 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2927 PLIGHTINFOEL *lightInfo = NULL;
2928 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2930 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2931 TRACE("(%p) : for idx(%d)\n", This, Index);
2933 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2934 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2935 if(lightInfo->OriginalIndex == Index) break;
2939 if (lightInfo == NULL) {
2940 TRACE("Light enabled state requested but light not defined\n");
2941 return WINED3DERR_INVALIDCALL;
2943 /* true is 128 according to SetLightEnable */
2944 *pEnable = lightInfo->enabled ? 128 : 0;
2949 * Get / Set Clip Planes
2951 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2952 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2953 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2955 /* Validate Index */
2956 if (Index >= GL_LIMITS(clipplanes)) {
2957 TRACE("Application has requested clipplane this device doesn't support\n");
2958 return WINED3DERR_INVALIDCALL;
2961 This->updateStateBlock->changed.clipplane |= 1 << Index;
2963 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2964 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2965 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2966 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2967 TRACE("Application is setting old values over, nothing to do\n");
2971 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2972 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2973 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2974 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2976 /* Handle recording of state blocks */
2977 if (This->isRecordingState) {
2978 TRACE("Recording... not performing anything\n");
2982 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2987 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2988 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2989 TRACE("(%p) : for idx %d\n", This, Index);
2991 /* Validate Index */
2992 if (Index >= GL_LIMITS(clipplanes)) {
2993 TRACE("Application has requested clipplane this device doesn't support\n");
2994 return WINED3DERR_INVALIDCALL;
2997 pPlane[0] = This->stateBlock->clipplane[Index][0];
2998 pPlane[1] = This->stateBlock->clipplane[Index][1];
2999 pPlane[2] = This->stateBlock->clipplane[Index][2];
3000 pPlane[3] = This->stateBlock->clipplane[Index][3];
3005 * Get / Set Clip Plane Status
3006 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3008 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3009 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3010 FIXME("(%p) : stub\n", This);
3011 if (NULL == pClipStatus) {
3012 return WINED3DERR_INVALIDCALL;
3014 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3015 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3019 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3020 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3021 FIXME("(%p) : stub\n", This);
3022 if (NULL == pClipStatus) {
3023 return WINED3DERR_INVALIDCALL;
3025 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3026 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3031 * Get / Set Material
3033 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3034 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3036 This->updateStateBlock->changed.material = TRUE;
3037 This->updateStateBlock->material = *pMaterial;
3039 /* Handle recording of state blocks */
3040 if (This->isRecordingState) {
3041 TRACE("Recording... not performing anything\n");
3045 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3049 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3050 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3051 *pMaterial = This->updateStateBlock->material;
3052 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3053 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3054 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3055 pMaterial->Ambient.b, pMaterial->Ambient.a);
3056 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3057 pMaterial->Specular.b, pMaterial->Specular.a);
3058 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3059 pMaterial->Emissive.b, pMaterial->Emissive.a);
3060 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3068 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
3069 IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
3071 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3072 IWineD3DBuffer *oldIdxs;
3074 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3075 oldIdxs = This->updateStateBlock->pIndexData;
3077 This->updateStateBlock->changed.indices = TRUE;
3078 This->updateStateBlock->pIndexData = pIndexData;
3079 This->updateStateBlock->IndexFmt = fmt;
3081 /* Handle recording of state blocks */
3082 if (This->isRecordingState) {
3083 TRACE("Recording... not performing anything\n");
3084 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
3085 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
3089 if(oldIdxs != pIndexData) {
3090 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3092 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
3093 IWineD3DBuffer_AddRef(pIndexData);
3096 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
3097 IWineD3DBuffer_Release(oldIdxs);
3104 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
3106 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3108 *ppIndexData = This->stateBlock->pIndexData;
3110 /* up ref count on ppindexdata */
3112 IWineD3DBuffer_AddRef(*ppIndexData);
3113 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3115 TRACE("(%p) No index data set\n", This);
3117 TRACE("Returning %p\n", *ppIndexData);
3122 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3123 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3124 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3125 TRACE("(%p)->(%d)\n", This, BaseIndex);
3127 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3128 TRACE("Application is setting the old value over, nothing to do\n");
3132 This->updateStateBlock->baseVertexIndex = BaseIndex;
3134 if (This->isRecordingState) {
3135 TRACE("Recording... not performing anything\n");
3138 /* The base vertex index affects the stream sources */
3139 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3143 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3145 TRACE("(%p) : base_index %p\n", This, base_index);
3147 *base_index = This->stateBlock->baseVertexIndex;
3149 TRACE("Returning %u\n", *base_index);
3155 * Get / Set Viewports
3157 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3160 TRACE("(%p)\n", This);
3161 This->updateStateBlock->changed.viewport = TRUE;
3162 This->updateStateBlock->viewport = *pViewport;
3164 /* Handle recording of state blocks */
3165 if (This->isRecordingState) {
3166 TRACE("Recording... not performing anything\n");
3170 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3171 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3173 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3178 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3179 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3180 TRACE("(%p)\n", This);
3181 *pViewport = This->stateBlock->viewport;
3186 * Get / Set Render States
3187 * TODO: Verify against dx9 definitions
3189 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3191 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3192 DWORD oldValue = This->stateBlock->renderState[State];
3194 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3196 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3197 This->updateStateBlock->renderState[State] = Value;
3199 /* Handle recording of state blocks */
3200 if (This->isRecordingState) {
3201 TRACE("Recording... not performing anything\n");
3205 /* Compared here and not before the assignment to allow proper stateblock recording */
3206 if(Value == oldValue) {
3207 TRACE("Application is setting the old value over, nothing to do\n");
3209 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3215 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3216 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3217 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3218 *pValue = This->stateBlock->renderState[State];
3223 * Get / Set Sampler States
3224 * TODO: Verify against dx9 definitions
3227 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3228 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3231 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3232 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3234 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3235 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3238 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3239 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3240 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3243 * SetSampler is designed to allow for more than the standard up to 8 textures
3244 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3245 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3247 * http://developer.nvidia.com/object/General_FAQ.html#t6
3249 * There are two new settings for GForce
3251 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3252 * and the texture one:
3253 * GL_MAX_TEXTURE_COORDS_ARB.
3254 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3257 oldValue = This->stateBlock->samplerState[Sampler][Type];
3258 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3259 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3261 /* Handle recording of state blocks */
3262 if (This->isRecordingState) {
3263 TRACE("Recording... not performing anything\n");
3267 if(oldValue == Value) {
3268 TRACE("Application is setting the old value over, nothing to do\n");
3272 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3277 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3278 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3280 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3281 This, Sampler, debug_d3dsamplerstate(Type), Type);
3283 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3284 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3287 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3288 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3289 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3291 *Value = This->stateBlock->samplerState[Sampler][Type];
3292 TRACE("(%p) : Returning %#x\n", This, *Value);
3297 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3300 This->updateStateBlock->changed.scissorRect = TRUE;
3301 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3302 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3305 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3307 if(This->isRecordingState) {
3308 TRACE("Recording... not performing anything\n");
3312 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3317 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3318 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3320 *pRect = This->updateStateBlock->scissorRect;
3321 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3325 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3326 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3327 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3329 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3331 This->updateStateBlock->vertexDecl = pDecl;
3332 This->updateStateBlock->changed.vertexDecl = TRUE;
3334 if (This->isRecordingState) {
3335 TRACE("Recording... not performing anything\n");
3337 } else if(pDecl == oldDecl) {
3338 /* Checked after the assignment to allow proper stateblock recording */
3339 TRACE("Application is setting the old declaration over, nothing to do\n");
3343 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3347 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3348 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3350 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3352 *ppDecl = This->stateBlock->vertexDecl;
3353 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3357 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3358 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3359 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3361 This->updateStateBlock->vertexShader = pShader;
3362 This->updateStateBlock->changed.vertexShader = TRUE;
3364 if (This->isRecordingState) {
3365 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3366 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3367 TRACE("Recording... not performing anything\n");
3369 } else if(oldShader == pShader) {
3370 /* Checked here to allow proper stateblock recording */
3371 TRACE("App is setting the old shader over, nothing to do\n");
3375 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3376 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3377 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3379 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3384 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3387 if (NULL == ppShader) {
3388 return WINED3DERR_INVALIDCALL;
3390 *ppShader = This->stateBlock->vertexShader;
3391 if( NULL != *ppShader)
3392 IWineD3DVertexShader_AddRef(*ppShader);
3394 TRACE("(%p) : returning %p\n", This, *ppShader);
3398 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3399 IWineD3DDevice *iface,
3401 CONST BOOL *srcData,
3404 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3405 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3407 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3408 iface, srcData, start, count);
3410 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3412 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3413 for (i = 0; i < cnt; i++)
3414 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3416 for (i = start; i < cnt + start; ++i) {
3417 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3420 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3425 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3426 IWineD3DDevice *iface,
3431 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3432 int cnt = min(count, MAX_CONST_B - start);
3434 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3435 iface, dstData, start, count);
3437 if (dstData == NULL || cnt < 0)
3438 return WINED3DERR_INVALIDCALL;
3440 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3444 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3445 IWineD3DDevice *iface,
3450 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3451 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3453 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3454 iface, srcData, start, count);
3456 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3458 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3459 for (i = 0; i < cnt; i++)
3460 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3461 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3463 for (i = start; i < cnt + start; ++i) {
3464 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3467 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3472 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3473 IWineD3DDevice *iface,
3478 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3479 int cnt = min(count, MAX_CONST_I - start);
3481 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3482 iface, dstData, start, count);
3484 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3485 return WINED3DERR_INVALIDCALL;
3487 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3491 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3492 IWineD3DDevice *iface,
3494 CONST float *srcData,
3497 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3500 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3501 iface, srcData, start, count);
3503 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3504 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3505 return WINED3DERR_INVALIDCALL;
3507 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3509 for (i = 0; i < count; i++)
3510 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3511 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3514 if (!This->isRecordingState)
3516 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3517 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3520 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3521 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3526 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3527 IWineD3DDevice *iface,
3532 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3533 int cnt = min(count, This->d3d_vshader_constantF - start);
3535 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3536 iface, dstData, start, count);
3538 if (dstData == NULL || cnt < 0)
3539 return WINED3DERR_INVALIDCALL;
3541 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3545 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3547 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3549 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3553 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3555 DWORD i = This->rev_tex_unit_map[unit];
3556 DWORD j = This->texUnitMap[stage];
3558 This->texUnitMap[stage] = unit;
3559 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3561 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3564 This->rev_tex_unit_map[unit] = stage;
3565 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3567 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3571 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3574 This->fixed_function_usage_map = 0;
3575 for (i = 0; i < MAX_TEXTURES; ++i) {
3576 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3577 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3578 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3579 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3580 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3581 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3582 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3583 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3585 if (color_op == WINED3DTOP_DISABLE) {
3586 /* Not used, and disable higher stages */
3590 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3591 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3592 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3593 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3594 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3595 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3596 This->fixed_function_usage_map |= (1 << i);
3599 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3600 This->fixed_function_usage_map |= (1 << (i + 1));
3605 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3606 unsigned int i, tex;
3609 device_update_fixed_function_usage_map(This);
3610 ffu_map = This->fixed_function_usage_map;
3612 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3613 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3614 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3616 if (!(ffu_map & 1)) continue;
3618 if (This->texUnitMap[i] != i) {
3619 device_map_stage(This, i, i);
3620 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3621 markTextureStagesDirty(This, i);
3627 /* Now work out the mapping */
3629 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3631 if (!(ffu_map & 1)) continue;
3633 if (This->texUnitMap[i] != tex) {
3634 device_map_stage(This, i, tex);
3635 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3636 markTextureStagesDirty(This, i);
3643 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3644 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3645 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3648 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3649 if (sampler_type[i] && This->texUnitMap[i] != i)
3651 device_map_stage(This, i, i);
3652 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3653 if (i < MAX_TEXTURES) {
3654 markTextureStagesDirty(This, i);
3660 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3661 const DWORD *vshader_sampler_tokens, DWORD unit)
3663 DWORD current_mapping = This->rev_tex_unit_map[unit];
3665 /* Not currently used */
3666 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3668 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3669 /* Used by a fragment sampler */
3671 if (!pshader_sampler_tokens) {
3672 /* No pixel shader, check fixed function */
3673 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3676 /* Pixel shader, check the shader's sampler map */
3677 return !pshader_sampler_tokens[current_mapping];
3680 /* Used by a vertex sampler */
3681 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3684 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3685 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3686 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3687 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3688 int start = min(MAX_COMBINED_SAMPLERS, GL_LIMITS(combined_samplers)) - 1;
3692 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3694 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3695 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3696 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3699 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3700 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3701 if (vshader_sampler_type[i])
3703 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3705 /* Already mapped somewhere */
3709 while (start >= 0) {
3710 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3712 device_map_stage(This, vsampler_idx, start);
3713 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3725 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3726 BOOL vs = use_vs(This->stateBlock);
3727 BOOL ps = use_ps(This->stateBlock);
3730 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3731 * that would be really messy and require shader recompilation
3732 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3733 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3736 device_map_psamplers(This);
3738 device_map_fixed_function_samplers(This);
3742 device_map_vsamplers(This, ps);
3746 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3747 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3748 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3749 This->updateStateBlock->pixelShader = pShader;
3750 This->updateStateBlock->changed.pixelShader = TRUE;
3752 /* Handle recording of state blocks */
3753 if (This->isRecordingState) {
3754 TRACE("Recording... not performing anything\n");
3757 if (This->isRecordingState) {
3758 TRACE("Recording... not performing anything\n");
3759 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3760 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3764 if(pShader == oldShader) {
3765 TRACE("App is setting the old pixel shader over, nothing to do\n");
3769 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3770 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3772 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3773 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3778 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3779 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3781 if (NULL == ppShader) {
3782 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3783 return WINED3DERR_INVALIDCALL;
3786 *ppShader = This->stateBlock->pixelShader;
3787 if (NULL != *ppShader) {
3788 IWineD3DPixelShader_AddRef(*ppShader);
3790 TRACE("(%p) : returning %p\n", This, *ppShader);
3794 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3795 IWineD3DDevice *iface,
3797 CONST BOOL *srcData,
3800 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3801 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3803 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3804 iface, srcData, start, count);
3806 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3808 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3809 for (i = 0; i < cnt; i++)
3810 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3812 for (i = start; i < cnt + start; ++i) {
3813 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3816 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3821 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3822 IWineD3DDevice *iface,
3827 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3828 int cnt = min(count, MAX_CONST_B - start);
3830 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3831 iface, dstData, start, count);
3833 if (dstData == NULL || cnt < 0)
3834 return WINED3DERR_INVALIDCALL;
3836 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3840 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3841 IWineD3DDevice *iface,
3846 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3847 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3849 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3850 iface, srcData, start, count);
3852 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3854 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3855 for (i = 0; i < cnt; i++)
3856 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3857 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3859 for (i = start; i < cnt + start; ++i) {
3860 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3863 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3868 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3869 IWineD3DDevice *iface,
3874 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3875 int cnt = min(count, MAX_CONST_I - start);
3877 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3878 iface, dstData, start, count);
3880 if (dstData == NULL || cnt < 0)
3881 return WINED3DERR_INVALIDCALL;
3883 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3887 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3888 IWineD3DDevice *iface,
3890 CONST float *srcData,
3893 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3896 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3897 iface, srcData, start, count);
3899 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3900 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3901 return WINED3DERR_INVALIDCALL;
3903 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3905 for (i = 0; i < count; i++)
3906 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3907 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3910 if (!This->isRecordingState)
3912 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3913 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3916 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3917 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3922 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3923 IWineD3DDevice *iface,
3928 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3929 int cnt = min(count, This->d3d_pshader_constantF - start);
3931 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3932 iface, dstData, start, count);
3934 if (dstData == NULL || cnt < 0)
3935 return WINED3DERR_INVALIDCALL;
3937 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3941 /* Context activation is done by the caller. */
3942 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3943 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3944 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3947 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3950 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3954 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3956 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3959 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3961 ERR("Source has no position mask\n");
3962 return WINED3DERR_INVALIDCALL;
3965 /* We might access VBOs from this code, so hold the lock */
3968 if (dest->resource.allocatedMemory == NULL) {
3969 buffer_get_sysmem(dest);
3972 /* Get a pointer into the destination vbo(create one if none exists) and
3973 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3975 if (!dest->buffer_object && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT))
3977 dest->flags |= WINED3D_BUFFER_CREATEBO;
3978 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3981 if (dest->buffer_object)
3983 unsigned char extrabytes = 0;
3984 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3985 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3986 * this may write 4 extra bytes beyond the area that should be written
3988 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3989 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3990 if(!dest_conv_addr) {
3991 ERR("Out of memory\n");
3992 /* Continue without storing converted vertices */
3994 dest_conv = dest_conv_addr;
3998 * a) WINED3DRS_CLIPPING is enabled
3999 * b) WINED3DVOP_CLIP is passed
4001 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4002 static BOOL warned = FALSE;
4004 * The clipping code is not quite correct. Some things need
4005 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4006 * so disable clipping for now.
4007 * (The graphics in Half-Life are broken, and my processvertices
4008 * test crashes with IDirect3DDevice3)
4014 FIXME("Clipping is broken and disabled for now\n");
4016 } else doClip = FALSE;
4017 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4019 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4022 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4023 WINED3DTS_PROJECTION,
4025 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4026 WINED3DTS_WORLDMATRIX(0),
4029 TRACE("View mat:\n");
4030 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);
4031 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);
4032 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);
4033 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);
4035 TRACE("Proj mat:\n");
4036 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);
4037 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);
4038 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);
4039 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);
4041 TRACE("World mat:\n");
4042 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);
4043 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);
4044 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);
4045 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);
4047 /* Get the viewport */
4048 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4049 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4050 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4052 multiply_matrix(&mat,&view_mat,&world_mat);
4053 multiply_matrix(&mat,&proj_mat,&mat);
4055 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4057 for (i = 0; i < dwCount; i+= 1) {
4058 unsigned int tex_index;
4060 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4061 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4062 /* The position first */
4063 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
4064 const float *p = (const float *)(element->data + i * element->stride);
4066 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4068 /* Multiplication with world, view and projection matrix */
4069 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);
4070 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);
4071 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);
4072 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);
4074 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4076 /* WARNING: The following things are taken from d3d7 and were not yet checked
4077 * against d3d8 or d3d9!
4080 /* Clipping conditions: From msdn
4082 * A vertex is clipped if it does not match the following requirements
4086 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4088 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4089 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4094 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4095 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4098 /* "Normal" viewport transformation (not clipped)
4099 * 1) The values are divided by rhw
4100 * 2) The y axis is negative, so multiply it with -1
4101 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4102 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4103 * 4) Multiply x with Width/2 and add Width/2
4104 * 5) The same for the height
4105 * 6) Add the viewpoint X and Y to the 2D coordinates and
4106 * The minimum Z value to z
4107 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4109 * Well, basically it's simply a linear transformation into viewport
4121 z *= vp.MaxZ - vp.MinZ;
4123 x += vp.Width / 2 + vp.X;
4124 y += vp.Height / 2 + vp.Y;
4129 /* That vertex got clipped
4130 * Contrary to OpenGL it is not dropped completely, it just
4131 * undergoes a different calculation.
4133 TRACE("Vertex got clipped\n");
4140 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4141 * outside of the main vertex buffer memory. That needs some more
4146 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4149 ( (float *) dest_ptr)[0] = x;
4150 ( (float *) dest_ptr)[1] = y;
4151 ( (float *) dest_ptr)[2] = z;
4152 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4154 dest_ptr += 3 * sizeof(float);
4156 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4157 dest_ptr += sizeof(float);
4162 ( (float *) dest_conv)[0] = x * w;
4163 ( (float *) dest_conv)[1] = y * w;
4164 ( (float *) dest_conv)[2] = z * w;
4165 ( (float *) dest_conv)[3] = w;
4167 dest_conv += 3 * sizeof(float);
4169 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4170 dest_conv += sizeof(float);
4174 if (DestFVF & WINED3DFVF_PSIZE) {
4175 dest_ptr += sizeof(DWORD);
4176 if(dest_conv) dest_conv += sizeof(DWORD);
4178 if (DestFVF & WINED3DFVF_NORMAL) {
4179 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4180 const float *normal = (const float *)(element->data + i * element->stride);
4181 /* AFAIK this should go into the lighting information */
4182 FIXME("Didn't expect the destination to have a normal\n");
4183 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4185 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4189 if (DestFVF & WINED3DFVF_DIFFUSE) {
4190 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4191 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4192 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4194 static BOOL warned = FALSE;
4197 ERR("No diffuse color in source, but destination has one\n");
4201 *( (DWORD *) dest_ptr) = 0xffffffff;
4202 dest_ptr += sizeof(DWORD);
4205 *( (DWORD *) dest_conv) = 0xffffffff;
4206 dest_conv += sizeof(DWORD);
4210 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4212 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4213 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4214 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4215 dest_conv += sizeof(DWORD);
4220 if (DestFVF & WINED3DFVF_SPECULAR)
4222 /* What's the color value in the feedback buffer? */
4223 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4224 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4225 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4227 static BOOL warned = FALSE;
4230 ERR("No specular color in source, but destination has one\n");
4234 *( (DWORD *) dest_ptr) = 0xFF000000;
4235 dest_ptr += sizeof(DWORD);
4238 *( (DWORD *) dest_conv) = 0xFF000000;
4239 dest_conv += sizeof(DWORD);
4243 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4245 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4246 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4247 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4248 dest_conv += sizeof(DWORD);
4253 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4254 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4255 const float *tex_coord = (const float *)(element->data + i * element->stride);
4256 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4258 ERR("No source texture, but destination requests one\n");
4259 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4260 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4263 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4265 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4272 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4273 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4274 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4275 dwCount * get_flexible_vertex_size(DestFVF),
4277 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4278 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4285 #undef copy_and_next
4287 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4288 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4291 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4292 struct wined3d_stream_info stream_info;
4293 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4294 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4297 ERR("Output vertex declaration not implemented yet\n");
4300 /* Need any context to write to the vbo. */
4301 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
4303 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4304 * control the streamIsUP flag, thus restore it afterwards.
4306 This->stateBlock->streamIsUP = FALSE;
4307 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4308 This->stateBlock->streamIsUP = streamWasUP;
4310 if(vbo || SrcStartIndex) {
4312 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4313 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4315 * Also get the start index in, but only loop over all elements if there's something to add at all.
4317 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4319 struct wined3d_stream_info_element *e;
4321 if (!(stream_info.use_map & (1 << i))) continue;
4323 e = &stream_info.elements[i];
4324 if (e->buffer_object)
4326 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
4327 e->buffer_object = 0;
4328 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
4330 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4331 vb->buffer_object = 0;
4334 if (e->data) e->data += e->stride * SrcStartIndex;
4338 return process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4339 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4343 * Get / Set Texture Stage States
4344 * TODO: Verify against dx9 definitions
4346 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4347 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4348 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4350 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4352 if (Stage >= MAX_TEXTURES) {
4353 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4357 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4358 This->updateStateBlock->textureState[Stage][Type] = Value;
4360 if (This->isRecordingState) {
4361 TRACE("Recording... not performing anything\n");
4365 /* Checked after the assignments to allow proper stateblock recording */
4366 if(oldValue == Value) {
4367 TRACE("App is setting the old value over, nothing to do\n");
4371 if(Stage > This->stateBlock->lowest_disabled_stage &&
4372 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4373 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4374 * Changes in other states are important on disabled stages too
4379 if(Type == WINED3DTSS_COLOROP) {
4382 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4383 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4384 * they have to be disabled
4386 * The current stage is dirtified below.
4388 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4389 TRACE("Additionally dirtifying stage %u\n", i);
4390 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4392 This->stateBlock->lowest_disabled_stage = Stage;
4393 TRACE("New lowest disabled: %u\n", Stage);
4394 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4395 /* Previously disabled stage enabled. Stages above it may need enabling
4396 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4397 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4399 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4402 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4403 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4406 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4407 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4409 This->stateBlock->lowest_disabled_stage = i;
4410 TRACE("New lowest disabled: %u\n", i);
4414 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4419 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4420 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4421 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4422 *pValue = This->updateStateBlock->textureState[Stage][Type];
4429 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4430 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4431 IWineD3DBaseTexture *oldTexture;
4433 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4435 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4436 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4439 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4440 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4441 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4444 oldTexture = This->updateStateBlock->textures[Stage];
4446 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4447 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
4449 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4450 return WINED3DERR_INVALIDCALL;
4453 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4454 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4456 This->updateStateBlock->changed.textures |= 1 << Stage;
4457 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4458 This->updateStateBlock->textures[Stage] = pTexture;
4460 /* Handle recording of state blocks */
4461 if (This->isRecordingState) {
4462 TRACE("Recording... not performing anything\n");
4466 if(oldTexture == pTexture) {
4467 TRACE("App is setting the same texture again, nothing to do\n");
4471 /** NOTE: MSDN says that setTexture increases the reference count,
4472 * and that the application must set the texture back to null (or have a leaky application),
4473 * This means we should pass the refcount up to the parent
4474 *******************************/
4475 if (NULL != This->updateStateBlock->textures[Stage]) {
4476 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4477 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4478 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4480 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4482 if (!oldTexture || dimensions != IWineD3DBaseTexture_GetTextureDimensions(oldTexture))
4484 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4487 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4488 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4489 * so the COLOROP and ALPHAOP have to be dirtified.
4491 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4492 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4494 if(bindCount == 1) {
4495 new->baseTexture.sampler = Stage;
4497 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4501 if (NULL != oldTexture) {
4502 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4503 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4505 IWineD3DBaseTexture_Release(oldTexture);
4506 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4507 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4508 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4511 if(bindCount && old->baseTexture.sampler == Stage) {
4513 /* Have to do a search for the other sampler(s) where the texture is bound to
4514 * Shouldn't happen as long as apps bind a texture only to one stage
4516 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4517 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4518 if(This->updateStateBlock->textures[i] == oldTexture) {
4519 old->baseTexture.sampler = i;
4526 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4531 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4532 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4534 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4536 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4537 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4540 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4541 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4542 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4545 *ppTexture=This->stateBlock->textures[Stage];
4547 IWineD3DBaseTexture_AddRef(*ppTexture);
4549 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4557 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4558 IWineD3DSurface **ppBackBuffer) {
4559 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4560 IWineD3DSwapChain *swapChain;
4563 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4565 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4566 if (hr == WINED3D_OK) {
4567 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4568 IWineD3DSwapChain_Release(swapChain);
4570 *ppBackBuffer = NULL;
4575 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4576 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4577 WARN("(%p) : stub, calling idirect3d for now\n", This);
4578 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4581 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4583 IWineD3DSwapChain *swapChain;
4586 if(iSwapChain > 0) {
4587 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4588 if (hr == WINED3D_OK) {
4589 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4590 IWineD3DSwapChain_Release(swapChain);
4592 FIXME("(%p) Error getting display mode\n", This);
4595 /* Don't read the real display mode,
4596 but return the stored mode instead. X11 can't change the color
4597 depth, and some apps are pretty angry if they SetDisplayMode from
4598 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4600 Also don't relay to the swapchain because with ddraw it's possible
4601 that there isn't a swapchain at all */
4602 pMode->Width = This->ddraw_width;
4603 pMode->Height = This->ddraw_height;
4604 pMode->Format = This->ddraw_format;
4605 pMode->RefreshRate = 0;
4613 * Stateblock related functions
4616 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4617 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4618 IWineD3DStateBlock *stateblock;
4621 TRACE("(%p)\n", This);
4623 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4625 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4626 if (FAILED(hr)) return hr;
4628 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4629 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4630 This->isRecordingState = TRUE;
4632 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4637 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4638 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4640 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4642 if (!This->isRecordingState) {
4643 WARN("(%p) not recording! returning error\n", This);
4644 *ppStateBlock = NULL;
4645 return WINED3DERR_INVALIDCALL;
4648 for (i = 0; i <= WINEHIGHEST_RENDER_STATE >> 5; ++i)
4650 DWORD map = object->changed.renderState[i];
4651 for (j = 0; map; map >>= 1, ++j)
4653 if (!(map & 1)) continue;
4655 object->contained_render_states[object->num_contained_render_states++] = (i << 5) | j;
4659 for (i = 0; i <= HIGHEST_TRANSFORMSTATE >> 5; ++i)
4661 DWORD map = object->changed.transform[i];
4662 for (j = 0; map; map >>= 1, ++j)
4664 if (!(map & 1)) continue;
4666 object->contained_transform_states[object->num_contained_transform_states++] = (i << 5) | j;
4669 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4670 if(object->changed.vertexShaderConstantsF[i]) {
4671 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4672 object->num_contained_vs_consts_f++;
4675 for(i = 0; i < MAX_CONST_I; i++) {
4676 if (object->changed.vertexShaderConstantsI & (1 << i))
4678 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4679 object->num_contained_vs_consts_i++;
4682 for(i = 0; i < MAX_CONST_B; i++) {
4683 if (object->changed.vertexShaderConstantsB & (1 << i))
4685 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4686 object->num_contained_vs_consts_b++;
4689 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
4691 if (object->changed.pixelShaderConstantsF[i])
4693 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
4694 ++object->num_contained_ps_consts_f;
4697 for(i = 0; i < MAX_CONST_I; i++) {
4698 if (object->changed.pixelShaderConstantsI & (1 << i))
4700 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4701 object->num_contained_ps_consts_i++;
4704 for(i = 0; i < MAX_CONST_B; i++) {
4705 if (object->changed.pixelShaderConstantsB & (1 << i))
4707 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4708 object->num_contained_ps_consts_b++;
4711 for(i = 0; i < MAX_TEXTURES; i++) {
4712 DWORD map = object->changed.textureState[i];
4714 for(j = 0; map; map >>= 1, ++j)
4716 if (!(map & 1)) continue;
4718 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4719 object->contained_tss_states[object->num_contained_tss_states].state = j;
4720 ++object->num_contained_tss_states;
4723 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4724 DWORD map = object->changed.samplerState[i];
4726 for (j = 0; map; map >>= 1, ++j)
4728 if (!(map & 1)) continue;
4730 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4731 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4732 ++object->num_contained_sampler_states;
4736 *ppStateBlock = (IWineD3DStateBlock*) object;
4737 This->isRecordingState = FALSE;
4738 This->updateStateBlock = This->stateBlock;
4739 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4740 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4741 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4746 * Scene related functions
4748 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4749 /* At the moment we have no need for any functionality at the beginning
4751 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4752 TRACE("(%p)\n", This);
4755 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4756 return WINED3DERR_INVALIDCALL;
4758 This->inScene = TRUE;
4762 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4763 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4764 TRACE("(%p)\n", This);
4766 if(!This->inScene) {
4767 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4768 return WINED3DERR_INVALIDCALL;
4771 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
4772 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4774 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4778 This->inScene = FALSE;
4782 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4783 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4784 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4785 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4786 IWineD3DSwapChain *swapChain = NULL;
4788 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4790 TRACE("(%p) Presenting the frame\n", This);
4792 for(i = 0 ; i < swapchains ; i ++) {
4794 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4795 TRACE("presentinng chain %d, %p\n", i, swapChain);
4796 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4797 IWineD3DSwapChain_Release(swapChain);
4803 /* Not called from the VTable (internal subroutine) */
4804 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4805 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4806 float Z, DWORD Stencil) {
4807 GLbitfield glMask = 0;
4809 WINED3DRECT curRect;
4811 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4812 UINT drawable_width, drawable_height;
4813 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4814 IWineD3DSwapChainImpl *swapchain = NULL;
4815 struct wined3d_context *context;
4817 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4818 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4819 * for the cleared parts, and the untouched parts.
4821 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4822 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4823 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4824 * checking all this if the dest surface is in the drawable anyway.
4826 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4828 if(vp->X != 0 || vp->Y != 0 ||
4829 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4830 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4833 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4834 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4835 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4836 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4837 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4840 if(Count > 0 && pRects && (
4841 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4842 pRects[0].x2 < target->currentDesc.Width ||
4843 pRects[0].y2 < target->currentDesc.Height)) {
4844 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4851 context = ActivateContext(This, (IWineD3DSurface *)target, CTXUSAGE_CLEAR);
4853 target->get_drawable_size(context, &drawable_width, &drawable_height);
4857 /* Only set the values up once, as they are not changing */
4858 if (Flags & WINED3DCLEAR_STENCIL) {
4859 glClearStencil(Stencil);
4860 checkGLcall("glClearStencil");
4861 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4862 glStencilMask(0xFFFFFFFF);
4865 if (Flags & WINED3DCLEAR_ZBUFFER) {
4866 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4867 glDepthMask(GL_TRUE);
4869 checkGLcall("glClearDepth");
4870 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4871 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4873 if (vp->X != 0 || vp->Y != 0 ||
4874 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4875 surface_load_ds_location(This->stencilBufferTarget, context, location);
4877 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4878 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4879 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4880 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4881 surface_load_ds_location(This->stencilBufferTarget, context, location);
4883 else if (Count > 0 && pRects && (
4884 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4885 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4886 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4887 surface_load_ds_location(This->stencilBufferTarget, context, location);
4891 if (Flags & WINED3DCLEAR_TARGET) {
4892 TRACE("Clearing screen with glClear to color %x\n", Color);
4893 glClearColor(D3DCOLOR_R(Color),
4897 checkGLcall("glClearColor");
4899 /* Clear ALL colors! */
4900 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4901 glMask = glMask | GL_COLOR_BUFFER_BIT;
4904 vp_rect.left = vp->X;
4905 vp_rect.top = vp->Y;
4906 vp_rect.right = vp->X + vp->Width;
4907 vp_rect.bottom = vp->Y + vp->Height;
4908 if (!(Count > 0 && pRects)) {
4909 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4910 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4912 if (context->render_offscreen)
4914 glScissor(vp_rect.left, vp_rect.top,
4915 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4917 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4918 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4920 checkGLcall("glScissor");
4922 checkGLcall("glClear");
4924 /* Now process each rect in turn */
4925 for (i = 0; i < Count; i++) {
4926 /* Note gl uses lower left, width/height */
4927 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
4928 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4929 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4931 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4932 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4933 curRect.x1, (target->currentDesc.Height - curRect.y2),
4934 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4936 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4937 * The rectangle is not cleared, no error is returned, but further rectanlges are
4938 * still cleared if they are valid
4940 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4941 TRACE("Rectangle with negative dimensions, ignoring\n");
4945 if (context->render_offscreen)
4947 glScissor(curRect.x1, curRect.y1,
4948 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4950 glScissor(curRect.x1, drawable_height - curRect.y2,
4951 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4953 checkGLcall("glScissor");
4956 checkGLcall("glClear");
4960 /* Restore the old values (why..?) */
4961 if (Flags & WINED3DCLEAR_STENCIL) {
4962 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4964 if (Flags & WINED3DCLEAR_TARGET) {
4965 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4966 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4967 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4968 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4969 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4971 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4972 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4974 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
4976 if (Flags & WINED3DCLEAR_ZBUFFER) {
4977 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
4978 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4979 surface_modify_ds_location(This->stencilBufferTarget, location);
4984 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
4985 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
4988 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
4994 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4995 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4997 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4999 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5000 Count, pRects, Flags, Color, Z, Stencil);
5002 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5003 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5004 /* TODO: What about depth stencil buffers without stencil bits? */
5005 return WINED3DERR_INVALIDCALL;
5008 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5015 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
5016 WINED3DPRIMITIVETYPE primitive_type)
5018 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5020 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
5022 This->updateStateBlock->changed.primitive_type = TRUE;
5023 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
5026 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
5027 WINED3DPRIMITIVETYPE *primitive_type)
5029 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5031 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
5033 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
5035 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
5038 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
5040 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5042 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
5044 if(!This->stateBlock->vertexDecl) {
5045 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5046 return WINED3DERR_INVALIDCALL;
5049 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5050 if(This->stateBlock->streamIsUP) {
5051 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5052 This->stateBlock->streamIsUP = FALSE;
5055 if(This->stateBlock->loadBaseVertexIndex != 0) {
5056 This->stateBlock->loadBaseVertexIndex = 0;
5057 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5059 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5060 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
5064 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
5066 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5068 IWineD3DBuffer *pIB;
5071 pIB = This->stateBlock->pIndexData;
5073 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5074 * without an index buffer set. (The first time at least...)
5075 * D3D8 simply dies, but I doubt it can do much harm to return
5076 * D3DERR_INVALIDCALL there as well. */
5077 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5078 return WINED3DERR_INVALIDCALL;
5081 if(!This->stateBlock->vertexDecl) {
5082 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5083 return WINED3DERR_INVALIDCALL;
5086 if(This->stateBlock->streamIsUP) {
5087 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5088 This->stateBlock->streamIsUP = FALSE;
5090 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
5092 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
5094 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
5100 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5101 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5102 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5105 drawPrimitive(iface, index_count, startIndex, idxStride,
5106 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
5111 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
5112 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5114 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5117 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
5118 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
5120 if(!This->stateBlock->vertexDecl) {
5121 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5122 return WINED3DERR_INVALIDCALL;
5125 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5126 vb = This->stateBlock->streamSource[0];
5127 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5128 if (vb) IWineD3DBuffer_Release(vb);
5129 This->stateBlock->streamOffset[0] = 0;
5130 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5131 This->stateBlock->streamIsUP = TRUE;
5132 This->stateBlock->loadBaseVertexIndex = 0;
5134 /* TODO: Only mark dirty if drawing from a different UP address */
5135 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5137 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
5139 /* MSDN specifies stream zero settings must be set to NULL */
5140 This->stateBlock->streamStride[0] = 0;
5141 This->stateBlock->streamSource[0] = NULL;
5143 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5144 * the new stream sources or use UP drawing again
5149 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
5150 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
5151 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5158 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
5159 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5161 if(!This->stateBlock->vertexDecl) {
5162 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5163 return WINED3DERR_INVALIDCALL;
5166 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
5172 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5173 vb = This->stateBlock->streamSource[0];
5174 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5175 if (vb) IWineD3DBuffer_Release(vb);
5176 This->stateBlock->streamIsUP = TRUE;
5177 This->stateBlock->streamOffset[0] = 0;
5178 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5180 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5181 This->stateBlock->baseVertexIndex = 0;
5182 This->stateBlock->loadBaseVertexIndex = 0;
5183 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5184 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5185 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5187 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
5189 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5190 This->stateBlock->streamSource[0] = NULL;
5191 This->stateBlock->streamStride[0] = 0;
5192 ib = This->stateBlock->pIndexData;
5194 IWineD3DBuffer_Release(ib);
5195 This->stateBlock->pIndexData = NULL;
5197 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5198 * SetStreamSource to specify a vertex buffer
5204 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5205 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
5207 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5209 /* Mark the state dirty until we have nicer tracking
5210 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5213 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5214 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5215 This->stateBlock->baseVertexIndex = 0;
5216 This->up_strided = DrawPrimStrideData;
5217 drawPrimitive(iface, vertex_count, 0, 0, NULL);
5218 This->up_strided = NULL;
5222 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5223 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
5224 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
5226 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5227 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5229 /* Mark the state dirty until we have nicer tracking
5230 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5233 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5234 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5235 This->stateBlock->streamIsUP = TRUE;
5236 This->stateBlock->baseVertexIndex = 0;
5237 This->up_strided = DrawPrimStrideData;
5238 drawPrimitive(iface, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData);
5239 This->up_strided = NULL;
5243 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5244 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5245 * not callable by the app directly no parameter validation checks are needed here.
5247 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5248 WINED3DLOCKED_BOX src;
5249 WINED3DLOCKED_BOX dst;
5251 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5253 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5254 * dirtification to improve loading performance.
5256 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5257 if(FAILED(hr)) return hr;
5258 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5260 IWineD3DVolume_UnlockBox(pSourceVolume);
5264 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5266 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5268 IWineD3DVolume_UnlockBox(pSourceVolume);
5270 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5275 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5276 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5277 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5278 HRESULT hr = WINED3D_OK;
5279 WINED3DRESOURCETYPE sourceType;
5280 WINED3DRESOURCETYPE destinationType;
5283 /* TODO: think about moving the code into IWineD3DBaseTexture */
5285 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5287 /* verify that the source and destination textures aren't NULL */
5288 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5289 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5290 This, pSourceTexture, pDestinationTexture);
5291 hr = WINED3DERR_INVALIDCALL;
5294 if (pSourceTexture == pDestinationTexture) {
5295 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5296 This, pSourceTexture, pDestinationTexture);
5297 hr = WINED3DERR_INVALIDCALL;
5299 /* Verify that the source and destination textures are the same type */
5300 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5301 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5303 if (sourceType != destinationType) {
5304 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5306 hr = WINED3DERR_INVALIDCALL;
5309 /* check that both textures have the identical numbers of levels */
5310 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5311 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5312 hr = WINED3DERR_INVALIDCALL;
5315 if (WINED3D_OK == hr) {
5316 IWineD3DBaseTextureImpl *pDestImpl = (IWineD3DBaseTextureImpl *) pDestinationTexture;
5318 /* Make sure that the destination texture is loaded */
5319 pDestImpl->baseTexture.internal_preload(pDestinationTexture, SRGB_RGB);
5321 /* Update every surface level of the texture */
5322 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5324 switch (sourceType) {
5325 case WINED3DRTYPE_TEXTURE:
5327 IWineD3DSurface *srcSurface;
5328 IWineD3DSurface *destSurface;
5330 for (i = 0 ; i < levels ; ++i) {
5331 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5332 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5333 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5334 IWineD3DSurface_Release(srcSurface);
5335 IWineD3DSurface_Release(destSurface);
5336 if (WINED3D_OK != hr) {
5337 WARN("(%p) : Call to update surface failed\n", This);
5343 case WINED3DRTYPE_CUBETEXTURE:
5345 IWineD3DSurface *srcSurface;
5346 IWineD3DSurface *destSurface;
5347 WINED3DCUBEMAP_FACES faceType;
5349 for (i = 0 ; i < levels ; ++i) {
5350 /* Update each cube face */
5351 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5352 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5353 if (WINED3D_OK != hr) {
5354 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5356 TRACE("Got srcSurface %p\n", srcSurface);
5358 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5359 if (WINED3D_OK != hr) {
5360 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5362 TRACE("Got desrSurface %p\n", destSurface);
5364 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5365 IWineD3DSurface_Release(srcSurface);
5366 IWineD3DSurface_Release(destSurface);
5367 if (WINED3D_OK != hr) {
5368 WARN("(%p) : Call to update surface failed\n", This);
5376 case WINED3DRTYPE_VOLUMETEXTURE:
5378 IWineD3DVolume *srcVolume = NULL;
5379 IWineD3DVolume *destVolume = NULL;
5381 for (i = 0 ; i < levels ; ++i) {
5382 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5383 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5384 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5385 IWineD3DVolume_Release(srcVolume);
5386 IWineD3DVolume_Release(destVolume);
5387 if (WINED3D_OK != hr) {
5388 WARN("(%p) : Call to update volume failed\n", This);
5396 FIXME("(%p) : Unsupported source and destination type\n", This);
5397 hr = WINED3DERR_INVALIDCALL;
5404 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5405 IWineD3DSwapChain *swapChain;
5407 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5408 if(hr == WINED3D_OK) {
5409 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5410 IWineD3DSwapChain_Release(swapChain);
5415 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5416 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5417 IWineD3DBaseTextureImpl *texture;
5420 TRACE("(%p) : %p\n", This, pNumPasses);
5422 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5423 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5424 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5425 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5427 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5428 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5429 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5432 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5433 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5435 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5436 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5439 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5440 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5443 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5444 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5445 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5450 /* return a sensible default */
5453 TRACE("returning D3D_OK\n");
5457 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5461 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5463 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5464 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
5465 || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
5467 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5472 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5473 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5476 PALETTEENTRY **palettes;
5478 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5480 if (PaletteNumber >= MAX_PALETTES) {
5481 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5482 return WINED3DERR_INVALIDCALL;
5485 if (PaletteNumber >= This->NumberOfPalettes) {
5486 NewSize = This->NumberOfPalettes;
5489 } while(PaletteNumber >= NewSize);
5490 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5492 ERR("Out of memory!\n");
5493 return E_OUTOFMEMORY;
5495 This->palettes = palettes;
5496 This->NumberOfPalettes = NewSize;
5499 if (!This->palettes[PaletteNumber]) {
5500 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5501 if (!This->palettes[PaletteNumber]) {
5502 ERR("Out of memory!\n");
5503 return E_OUTOFMEMORY;
5507 for (j = 0; j < 256; ++j) {
5508 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5509 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5510 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5511 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5513 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5514 TRACE("(%p) : returning\n", This);
5518 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5519 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5521 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5522 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5523 /* What happens in such situation isn't documented; Native seems to silently abort
5524 on such conditions. Return Invalid Call. */
5525 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5526 return WINED3DERR_INVALIDCALL;
5528 for (j = 0; j < 256; ++j) {
5529 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5530 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5531 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5532 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5534 TRACE("(%p) : returning\n", This);
5538 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5540 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5541 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5542 (tested with reference rasterizer). Return Invalid Call. */
5543 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5544 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5545 return WINED3DERR_INVALIDCALL;
5547 /*TODO: stateblocks */
5548 if (This->currentPalette != PaletteNumber) {
5549 This->currentPalette = PaletteNumber;
5550 dirtify_p8_texture_samplers(This);
5552 TRACE("(%p) : returning\n", This);
5556 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5557 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5558 if (PaletteNumber == NULL) {
5559 WARN("(%p) : returning Invalid Call\n", This);
5560 return WINED3DERR_INVALIDCALL;
5562 /*TODO: stateblocks */
5563 *PaletteNumber = This->currentPalette;
5564 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5568 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5569 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5573 FIXME("(%p) : stub\n", This);
5577 This->softwareVertexProcessing = bSoftware;
5582 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5583 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5587 FIXME("(%p) : stub\n", This);
5590 return This->softwareVertexProcessing;
5594 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5595 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5596 IWineD3DSwapChain *swapChain;
5599 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5601 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5602 if(hr == WINED3D_OK){
5603 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5604 IWineD3DSwapChain_Release(swapChain);
5606 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5612 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5613 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5615 if(nSegments != 0.0f) {
5618 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5625 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5626 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5630 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5636 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5637 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5638 /** TODO: remove casts to IWineD3DSurfaceImpl
5639 * NOTE: move code to surface to accomplish this
5640 ****************************************/
5641 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5642 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)pDestinationSurface;
5643 int srcWidth, srcHeight;
5644 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5645 WINED3DFORMAT destFormat, srcFormat;
5647 int srcLeft, destLeft, destTop;
5648 WINED3DPOOL srcPool, destPool;
5650 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5651 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
5655 CONVERT_TYPES convert = NO_CONVERSION;
5657 WINED3DSURFACE_DESC winedesc;
5659 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5661 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5662 srcSurfaceWidth = winedesc.width;
5663 srcSurfaceHeight = winedesc.height;
5664 srcPool = winedesc.pool;
5665 srcFormat = winedesc.format;
5667 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5668 destSurfaceWidth = winedesc.width;
5669 destSurfaceHeight = winedesc.height;
5670 destPool = winedesc.pool;
5671 destFormat = winedesc.format;
5672 destSize = winedesc.size;
5674 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5675 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5676 return WINED3DERR_INVALIDCALL;
5679 /* This call loads the opengl surface directly, instead of copying the surface to the
5680 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5681 * copy in sysmem and use regular surface loading.
5683 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5684 if(convert != NO_CONVERSION) {
5685 return IWineD3DSurface_BltFast(pDestinationSurface,
5686 pDestPoint ? pDestPoint->x : 0,
5687 pDestPoint ? pDestPoint->y : 0,
5688 pSourceSurface, pSourceRect, 0);
5691 if (destFormat == WINED3DFMT_UNKNOWN) {
5692 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5693 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5695 /* Get the update surface description */
5696 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5699 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
5702 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5703 checkGLcall("glActiveTextureARB");
5706 /* Make sure the surface is loaded and up to date */
5707 surface_internal_preload(pDestinationSurface, SRGB_RGB);
5708 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5710 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
5711 dst_format_desc = dst_impl->resource.format_desc;
5713 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5714 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5715 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5716 srcLeft = pSourceRect ? pSourceRect->left : 0;
5717 destLeft = pDestPoint ? pDestPoint->x : 0;
5718 destTop = pDestPoint ? pDestPoint->y : 0;
5721 /* This function doesn't support compressed textures
5722 the pitch is just bytesPerPixel * width */
5723 if(srcWidth != srcSurfaceWidth || srcLeft ){
5724 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
5725 offset += srcLeft * src_format_desc->byte_count;
5726 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5728 /* TODO DXT formats */
5730 if(pSourceRect != NULL && pSourceRect->top != 0){
5731 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
5733 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5734 This, dst_impl->texture_level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
5735 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5738 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5740 /* need to lock the surface to get the data */
5741 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5746 /* TODO: Cube and volume support */
5748 /* not a whole row so we have to do it a line at a time */
5751 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5752 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5754 for (j = destTop; j < (srcHeight + destTop); ++j)
5756 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, j,
5757 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
5761 } else { /* Full width, so just write out the whole texture */
5762 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5764 if (dst_format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
5766 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth)
5768 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across. */
5769 FIXME("Updating part of a compressed texture is not supported.\n");
5771 if (destFormat != srcFormat)
5773 FIXME("Updating mixed format compressed textures is not supported.\n");
5777 GL_EXTCALL(glCompressedTexImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5778 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
5783 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, destTop,
5784 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
5787 checkGLcall("glTexSubImage2D");
5791 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5792 sampler = This->rev_tex_unit_map[0];
5793 if (sampler != WINED3D_UNMAPPED_STAGE)
5795 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5801 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5802 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5803 struct WineD3DRectPatch *patch;
5804 GLenum old_primitive_type;
5808 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5810 if(!(Handle || pRectPatchInfo)) {
5811 /* TODO: Write a test for the return value, thus the FIXME */
5812 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5813 return WINED3DERR_INVALIDCALL;
5817 i = PATCHMAP_HASHFUNC(Handle);
5819 LIST_FOR_EACH(e, &This->patches[i]) {
5820 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5821 if(patch->Handle == Handle) {
5828 TRACE("Patch does not exist. Creating a new one\n");
5829 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5830 patch->Handle = Handle;
5831 list_add_head(&This->patches[i], &patch->entry);
5833 TRACE("Found existing patch %p\n", patch);
5836 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5837 * attributes we have to tesselate, read back, and draw. This needs a patch
5838 * management structure instance. Create one.
5840 * A possible improvement is to check if a vertex shader is used, and if not directly
5843 FIXME("Drawing an uncached patch. This is slow\n");
5844 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5847 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5848 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5849 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5851 TRACE("Tesselation density or patch info changed, retesselating\n");
5853 if(pRectPatchInfo) {
5854 patch->RectPatchInfo = *pRectPatchInfo;
5856 patch->numSegs[0] = pNumSegs[0];
5857 patch->numSegs[1] = pNumSegs[1];
5858 patch->numSegs[2] = pNumSegs[2];
5859 patch->numSegs[3] = pNumSegs[3];
5861 hr = tesselate_rectpatch(This, patch);
5863 WARN("Patch tesselation failed\n");
5865 /* Do not release the handle to store the params of the patch */
5867 HeapFree(GetProcessHeap(), 0, patch);
5873 This->currentPatch = patch;
5874 old_primitive_type = This->stateBlock->gl_primitive_type;
5875 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5876 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5877 This->stateBlock->gl_primitive_type = old_primitive_type;
5878 This->currentPatch = NULL;
5880 /* Destroy uncached patches */
5882 HeapFree(GetProcessHeap(), 0, patch->mem);
5883 HeapFree(GetProcessHeap(), 0, patch);
5888 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5889 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5890 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5891 FIXME("(%p) : Stub\n", This);
5895 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5898 struct WineD3DRectPatch *patch;
5900 TRACE("(%p) Handle(%d)\n", This, Handle);
5902 i = PATCHMAP_HASHFUNC(Handle);
5903 LIST_FOR_EACH(e, &This->patches[i]) {
5904 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5905 if(patch->Handle == Handle) {
5906 TRACE("Deleting patch %p\n", patch);
5907 list_remove(&patch->entry);
5908 HeapFree(GetProcessHeap(), 0, patch->mem);
5909 HeapFree(GetProcessHeap(), 0, patch);
5914 /* TODO: Write a test for the return value */
5915 FIXME("Attempt to destroy nonexistent patch\n");
5916 return WINED3DERR_INVALIDCALL;
5919 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5921 IWineD3DSwapChain *swapchain;
5923 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5924 if (SUCCEEDED(hr)) {
5925 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5932 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
5933 const WINED3DRECT *rect, const float color[4])
5935 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5936 struct wined3d_context *context;
5937 IWineD3DSwapChain *swapchain;
5939 swapchain = get_swapchain(surface);
5943 TRACE("Surface %p is onscreen\n", surface);
5945 context = ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
5947 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
5948 buffer = surface_get_gl_buffer(surface, swapchain);
5949 glDrawBuffer(buffer);
5950 checkGLcall("glDrawBuffer()");
5952 TRACE("Surface %p is offscreen\n", surface);
5954 context = ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
5956 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
5957 context_attach_surface_fbo(context, GL_FRAMEBUFFER, 0, surface);
5958 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, NULL, FALSE);
5962 glEnable(GL_SCISSOR_TEST);
5964 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5966 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5967 rect->x2 - rect->x1, rect->y2 - rect->y1);
5969 checkGLcall("glScissor");
5970 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5972 glDisable(GL_SCISSOR_TEST);
5974 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5976 glDisable(GL_BLEND);
5977 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
5979 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5980 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5982 glClearColor(color[0], color[1], color[2], color[3]);
5983 glClear(GL_COLOR_BUFFER_BIT);
5984 checkGLcall("glClear");
5986 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5987 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5988 glDrawBuffer(GL_BACK);
5989 checkGLcall("glDrawBuffer()");
5995 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5996 unsigned int r, g, b, a;
5999 if (destfmt == WINED3DFMT_B8G8R8A8_UNORM
6000 || destfmt == WINED3DFMT_B8G8R8X8_UNORM
6001 || destfmt == WINED3DFMT_B8G8R8_UNORM)
6004 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6006 a = (color & 0xff000000) >> 24;
6007 r = (color & 0x00ff0000) >> 16;
6008 g = (color & 0x0000ff00) >> 8;
6009 b = (color & 0x000000ff) >> 0;
6013 case WINED3DFMT_B5G6R5_UNORM:
6014 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6021 TRACE("Returning %08x\n", ret);
6024 case WINED3DFMT_B5G5R5X1_UNORM:
6025 case WINED3DFMT_B5G5R5A1_UNORM:
6034 TRACE("Returning %08x\n", ret);
6037 case WINED3DFMT_A8_UNORM:
6038 TRACE("Returning %08x\n", a);
6041 case WINED3DFMT_B4G4R4X4_UNORM:
6042 case WINED3DFMT_B4G4R4A4_UNORM:
6051 TRACE("Returning %08x\n", ret);
6054 case WINED3DFMT_B2G3R3_UNORM:
6061 TRACE("Returning %08x\n", ret);
6064 case WINED3DFMT_R8G8B8X8_UNORM:
6065 case WINED3DFMT_R8G8B8A8_UNORM:
6070 TRACE("Returning %08x\n", ret);
6073 case WINED3DFMT_B10G10R10A2_UNORM:
6075 r = (r * 1024) / 256;
6076 g = (g * 1024) / 256;
6077 b = (b * 1024) / 256;
6082 TRACE("Returning %08x\n", ret);
6085 case WINED3DFMT_R10G10B10A2_UNORM:
6087 r = (r * 1024) / 256;
6088 g = (g * 1024) / 256;
6089 b = (b * 1024) / 256;
6094 TRACE("Returning %08x\n", ret);
6098 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6103 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6104 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6105 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6107 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6109 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6110 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6111 return WINED3DERR_INVALIDCALL;
6114 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6115 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
6116 color_fill_fbo(iface, pSurface, pRect, c);
6119 /* Just forward this to the DirectDraw blitting engine */
6120 memset(&BltFx, 0, sizeof(BltFx));
6121 BltFx.dwSize = sizeof(BltFx);
6122 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
6123 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6124 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
6128 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
6129 IWineD3DRendertargetView *rendertarget_view, const float color[4])
6131 IWineD3DResource *resource;
6132 IWineD3DSurface *surface;
6135 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
6138 ERR("Failed to get resource, hr %#x\n", hr);
6142 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
6144 FIXME("Only supported on surface resources\n");
6145 IWineD3DResource_Release(resource);
6149 surface = (IWineD3DSurface *)resource;
6151 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6153 color_fill_fbo(iface, surface, NULL, color);
6160 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
6162 c = ((DWORD)(color[2] * 255.0f));
6163 c |= ((DWORD)(color[1] * 255.0f)) << 8;
6164 c |= ((DWORD)(color[0] * 255.0f)) << 16;
6165 c |= ((DWORD)(color[3] * 255.0f)) << 24;
6167 /* Just forward this to the DirectDraw blitting engine */
6168 memset(&BltFx, 0, sizeof(BltFx));
6169 BltFx.dwSize = sizeof(BltFx);
6170 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
6171 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
6174 ERR("Blt failed, hr %#x\n", hr);
6178 IWineD3DResource_Release(resource);
6181 /* rendertarget and depth stencil functions */
6182 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6183 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6185 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6186 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6187 return WINED3DERR_INVALIDCALL;
6190 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6191 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6192 /* Note inc ref on returned surface */
6193 if(*ppRenderTarget != NULL)
6194 IWineD3DSurface_AddRef(*ppRenderTarget);
6198 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6199 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6200 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6201 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6202 IWineD3DSwapChainImpl *Swapchain;
6205 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6207 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6208 if(hr != WINED3D_OK) {
6209 ERR("Can't get the swapchain\n");
6213 /* Make sure to release the swapchain */
6214 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6216 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6217 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6218 return WINED3DERR_INVALIDCALL;
6220 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6221 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6222 return WINED3DERR_INVALIDCALL;
6225 if(Swapchain->frontBuffer != Front) {
6226 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6228 if(Swapchain->frontBuffer)
6230 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6231 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
6233 Swapchain->frontBuffer = Front;
6235 if(Swapchain->frontBuffer) {
6236 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6237 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
6241 if(Back && !Swapchain->backBuffer) {
6242 /* We need memory for the back buffer array - only one back buffer this way */
6243 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6244 if(!Swapchain->backBuffer) {
6245 ERR("Out of memory\n");
6246 return E_OUTOFMEMORY;
6250 if(Swapchain->backBuffer[0] != Back) {
6251 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6253 /* What to do about the context here in the case of multithreading? Not sure.
6254 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6256 WARN("No active context?\n");
6259 if(!Swapchain->backBuffer[0]) {
6260 /* GL was told to draw to the front buffer at creation,
6263 glDrawBuffer(GL_BACK);
6264 checkGLcall("glDrawBuffer(GL_BACK)");
6265 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6266 Swapchain->presentParms.BackBufferCount = 1;
6268 /* That makes problems - disable for now */
6269 /* glDrawBuffer(GL_FRONT); */
6270 checkGLcall("glDrawBuffer(GL_FRONT)");
6271 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6272 Swapchain->presentParms.BackBufferCount = 0;
6276 if(Swapchain->backBuffer[0])
6278 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6279 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
6281 Swapchain->backBuffer[0] = Back;
6283 if(Swapchain->backBuffer[0]) {
6284 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6285 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
6287 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6288 Swapchain->backBuffer = NULL;
6296 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6298 *ppZStencilSurface = This->stencilBufferTarget;
6299 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6301 if(*ppZStencilSurface != NULL) {
6302 /* Note inc ref on returned surface */
6303 IWineD3DSurface_AddRef(*ppZStencilSurface);
6306 return WINED3DERR_NOTFOUND;
6310 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6311 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6313 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6314 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6315 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6316 const struct wined3d_gl_info *gl_info;
6317 struct wined3d_context *context;
6319 POINT offset = {0, 0};
6321 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6322 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6323 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6324 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6327 case WINED3DTEXF_LINEAR:
6328 gl_filter = GL_LINEAR;
6332 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6333 case WINED3DTEXF_NONE:
6334 case WINED3DTEXF_POINT:
6335 gl_filter = GL_NEAREST;
6339 /* Attach src surface to src fbo */
6340 src_swapchain = get_swapchain(src_surface);
6341 dst_swapchain = get_swapchain(dst_surface);
6343 if (src_swapchain) context = ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6344 else if (dst_swapchain) context = ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6345 else context = ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6347 gl_info = context->gl_info;
6349 if (src_swapchain) {
6350 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6352 TRACE("Source surface %p is onscreen\n", src_surface);
6353 /* Make sure the drawable is up to date. In the offscreen case
6354 * attach_surface_fbo() implicitly takes care of this. */
6355 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6357 if(buffer == GL_FRONT) {
6360 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6361 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6362 h = windowsize.bottom - windowsize.top;
6363 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6364 src_rect->y1 = offset.y + h - src_rect->y1;
6365 src_rect->y2 = offset.y + h - src_rect->y2;
6367 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6368 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6372 context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
6373 glReadBuffer(buffer);
6374 checkGLcall("glReadBuffer()");
6376 TRACE("Source surface %p is offscreen\n", src_surface);
6378 context_bind_fbo(context, GL_READ_FRAMEBUFFER, &context->src_fbo);
6379 context_attach_surface_fbo(context, GL_READ_FRAMEBUFFER, 0, src_surface);
6380 glReadBuffer(GL_COLOR_ATTACHMENT0);
6381 checkGLcall("glReadBuffer()");
6382 context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER, NULL, FALSE);
6386 /* Attach dst surface to dst fbo */
6387 if (dst_swapchain) {
6388 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6390 TRACE("Destination surface %p is onscreen\n", dst_surface);
6391 /* Make sure the drawable is up to date. In the offscreen case
6392 * attach_surface_fbo() implicitly takes care of this. */
6393 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6395 if(buffer == GL_FRONT) {
6398 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6399 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6400 h = windowsize.bottom - windowsize.top;
6401 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6402 dst_rect->y1 = offset.y + h - dst_rect->y1;
6403 dst_rect->y2 = offset.y + h - dst_rect->y2;
6405 /* Screen coords = window coords, surface height = window height */
6406 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6407 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6411 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
6412 glDrawBuffer(buffer);
6413 checkGLcall("glDrawBuffer()");
6415 TRACE("Destination surface %p is offscreen\n", dst_surface);
6418 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, &context->dst_fbo);
6419 context_attach_surface_fbo(context, GL_DRAW_FRAMEBUFFER, 0, dst_surface);
6420 glDrawBuffer(GL_COLOR_ATTACHMENT0);
6421 checkGLcall("glDrawBuffer()");
6422 context_attach_depth_stencil_fbo(context, GL_DRAW_FRAMEBUFFER, NULL, FALSE);
6424 glDisable(GL_SCISSOR_TEST);
6425 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6428 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6429 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter);
6430 checkGLcall("glBlitFramebuffer()");
6432 gl_info->fbo_ops.glBlitFramebuffer(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6433 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter);
6434 checkGLcall("glBlitFramebuffer()");
6437 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6439 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6440 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6441 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6442 glDrawBuffer(GL_BACK);
6443 checkGLcall("glDrawBuffer()");
6448 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6449 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6450 WINED3DVIEWPORT viewport;
6452 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6454 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6455 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6456 This, RenderTargetIndex, GL_LIMITS(buffers));
6457 return WINED3DERR_INVALIDCALL;
6460 /* MSDN says that null disables the render target
6461 but a device must always be associated with a render target
6462 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6464 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6465 FIXME("Trying to set render target 0 to NULL\n");
6466 return WINED3DERR_INVALIDCALL;
6468 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6469 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);
6470 return WINED3DERR_INVALIDCALL;
6473 /* If we are trying to set what we already have, don't bother */
6474 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6475 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6478 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6479 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6480 This->render_targets[RenderTargetIndex] = pRenderTarget;
6482 /* Render target 0 is special */
6483 if(RenderTargetIndex == 0) {
6484 /* Finally, reset the viewport as the MSDN states. */
6485 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6486 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6489 viewport.MaxZ = 1.0f;
6490 viewport.MinZ = 0.0f;
6491 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6496 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6497 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6498 HRESULT hr = WINED3D_OK;
6499 IWineD3DSurface *tmp;
6501 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6503 if (pNewZStencil == This->stencilBufferTarget) {
6504 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6506 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6507 * depending on the renter target implementation being used.
6508 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6509 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6510 * stencil buffer and incur an extra memory overhead
6511 ******************************************************/
6513 if (This->stencilBufferTarget) {
6514 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6515 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6516 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6518 struct wined3d_context *context = ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6519 surface_load_ds_location(This->stencilBufferTarget, context, SFLAG_DS_OFFSCREEN);
6520 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6524 tmp = This->stencilBufferTarget;
6525 This->stencilBufferTarget = pNewZStencil;
6526 /* should we be calling the parent or the wined3d surface? */
6527 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6528 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6531 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6532 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6533 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6534 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6535 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6542 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6543 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6544 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6545 /* TODO: the use of Impl is deprecated. */
6546 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6547 WINED3DLOCKED_RECT lockedRect;
6549 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6551 /* some basic validation checks */
6552 if(This->cursorTexture) {
6553 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6555 glDeleteTextures(1, &This->cursorTexture);
6557 This->cursorTexture = 0;
6560 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6561 This->haveHardwareCursor = TRUE;
6563 This->haveHardwareCursor = FALSE;
6566 WINED3DLOCKED_RECT rect;
6568 /* MSDN: Cursor must be A8R8G8B8 */
6569 if (pSur->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
6571 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6572 return WINED3DERR_INVALIDCALL;
6575 /* MSDN: Cursor must be smaller than the display mode */
6576 if(pSur->currentDesc.Width > This->ddraw_width ||
6577 pSur->currentDesc.Height > This->ddraw_height) {
6578 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);
6579 return WINED3DERR_INVALIDCALL;
6582 if (!This->haveHardwareCursor) {
6583 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6585 /* Do not store the surface's pointer because the application may
6586 * release it after setting the cursor image. Windows doesn't
6587 * addref the set surface, so we can't do this either without
6588 * creating circular refcount dependencies. Copy out the gl texture
6591 This->cursorWidth = pSur->currentDesc.Width;
6592 This->cursorHeight = pSur->currentDesc.Height;
6593 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6595 const struct GlPixelFormatDesc *glDesc =
6596 getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, &GLINFO_LOCATION);
6597 char *mem, *bits = rect.pBits;
6598 GLint intfmt = glDesc->glInternal;
6599 GLint format = glDesc->glFormat;
6600 GLint type = glDesc->glType;
6601 INT height = This->cursorHeight;
6602 INT width = This->cursorWidth;
6603 INT bpp = glDesc->byte_count;
6607 /* Reformat the texture memory (pitch and width can be
6609 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6610 for(i = 0; i < height; i++)
6611 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6612 IWineD3DSurface_UnlockRect(pCursorBitmap);
6614 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6618 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6619 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6620 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6623 /* Make sure that a proper texture unit is selected */
6624 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6625 checkGLcall("glActiveTextureARB");
6626 sampler = This->rev_tex_unit_map[0];
6627 if (sampler != WINED3D_UNMAPPED_STAGE)
6629 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6631 /* Create a new cursor texture */
6632 glGenTextures(1, &This->cursorTexture);
6633 checkGLcall("glGenTextures");
6634 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6635 checkGLcall("glBindTexture");
6636 /* Copy the bitmap memory into the cursor texture */
6637 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6638 HeapFree(GetProcessHeap(), 0, mem);
6639 checkGLcall("glTexImage2D");
6641 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6642 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6643 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6650 FIXME("A cursor texture was not returned.\n");
6651 This->cursorTexture = 0;
6656 /* Draw a hardware cursor */
6657 ICONINFO cursorInfo;
6659 /* Create and clear maskBits because it is not needed for
6660 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6662 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6663 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6664 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6665 WINED3DLOCK_NO_DIRTY_UPDATE |
6666 WINED3DLOCK_READONLY
6668 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6669 pSur->currentDesc.Height);
6671 cursorInfo.fIcon = FALSE;
6672 cursorInfo.xHotspot = XHotSpot;
6673 cursorInfo.yHotspot = YHotSpot;
6674 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6675 pSur->currentDesc.Height, 1,
6677 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6678 pSur->currentDesc.Height, 1,
6679 32, lockedRect.pBits);
6680 IWineD3DSurface_UnlockRect(pCursorBitmap);
6681 /* Create our cursor and clean up. */
6682 cursor = CreateIconIndirect(&cursorInfo);
6684 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6685 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6686 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6687 This->hardwareCursor = cursor;
6688 HeapFree(GetProcessHeap(), 0, maskBits);
6692 This->xHotSpot = XHotSpot;
6693 This->yHotSpot = YHotSpot;
6697 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6698 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6699 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6701 This->xScreenSpace = XScreenSpace;
6702 This->yScreenSpace = YScreenSpace;
6708 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6709 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6710 BOOL oldVisible = This->bCursorVisible;
6713 TRACE("(%p) : visible(%d)\n", This, bShow);
6716 * When ShowCursor is first called it should make the cursor appear at the OS's last
6717 * known cursor position. Because of this, some applications just repetitively call
6718 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6721 This->xScreenSpace = pt.x;
6722 This->yScreenSpace = pt.y;
6724 if (This->haveHardwareCursor) {
6725 This->bCursorVisible = bShow;
6727 SetCursor(This->hardwareCursor);
6733 if (This->cursorTexture)
6734 This->bCursorVisible = bShow;
6740 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6741 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6742 IWineD3DResourceImpl *resource;
6743 TRACE("(%p) : state (%u)\n", This, This->state);
6745 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6746 switch (This->state) {
6749 case WINED3DERR_DEVICELOST:
6751 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6752 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6753 return WINED3DERR_DEVICENOTRESET;
6755 return WINED3DERR_DEVICELOST;
6757 case WINED3DERR_DRIVERINTERNALERROR:
6758 return WINED3DERR_DRIVERINTERNALERROR;
6762 return WINED3DERR_DRIVERINTERNALERROR;
6765 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6766 TRACE("checking resource %p for eviction\n", resource);
6767 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6768 TRACE("Evicting %p\n", resource);
6769 IWineD3DResource_UnLoad(resource);
6771 IWineD3DResource_Release(resource);
6775 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6776 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6777 TRACE("(%p)\n", This);
6779 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6783 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6785 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6787 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6788 if(surface->Flags & SFLAG_DIBSECTION) {
6789 /* Release the DC */
6790 SelectObject(surface->hDC, surface->dib.holdbitmap);
6791 DeleteDC(surface->hDC);
6792 /* Release the DIB section */
6793 DeleteObject(surface->dib.DIBsection);
6794 surface->dib.bitmap_data = NULL;
6795 surface->resource.allocatedMemory = NULL;
6796 surface->Flags &= ~SFLAG_DIBSECTION;
6798 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6799 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6800 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
6801 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
6802 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6803 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6805 surface->pow2Width = surface->pow2Height = 1;
6806 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6807 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6809 surface->glRect.left = 0;
6810 surface->glRect.top = 0;
6811 surface->glRect.right = surface->pow2Width;
6812 surface->glRect.bottom = surface->pow2Height;
6814 if (surface->texture_name)
6816 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6818 glDeleteTextures(1, &surface->texture_name);
6820 surface->texture_name = 0;
6821 surface->Flags &= ~SFLAG_CLIENT;
6823 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6824 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6825 surface->Flags |= SFLAG_NONPOW2;
6827 surface->Flags &= ~SFLAG_NONPOW2;
6829 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6830 surface->resource.allocatedMemory = NULL;
6831 surface->resource.heapMemory = NULL;
6832 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6833 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
6834 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
6835 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
6837 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
6841 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6842 TRACE("Unloading resource %p\n", resource);
6843 IWineD3DResource_UnLoad(resource);
6844 IWineD3DResource_Release(resource);
6848 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6851 WINED3DDISPLAYMODE m;
6854 /* All Windowed modes are supported, as is leaving the current mode */
6855 if(pp->Windowed) return TRUE;
6856 if(!pp->BackBufferWidth) return TRUE;
6857 if(!pp->BackBufferHeight) return TRUE;
6859 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
6860 for(i = 0; i < count; i++) {
6861 memset(&m, 0, sizeof(m));
6862 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
6864 ERR("EnumAdapterModes failed\n");
6866 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6867 /* Mode found, it is supported */
6871 /* Mode not found -> not supported */
6875 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6876 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6877 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6878 const struct wined3d_context *context;
6879 const struct wined3d_gl_info *gl_info;
6881 IWineD3DBaseShaderImpl *shader;
6883 context = ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6884 gl_info = context->gl_info;
6886 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6887 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6888 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6892 if(This->depth_blt_texture) {
6893 glDeleteTextures(1, &This->depth_blt_texture);
6894 This->depth_blt_texture = 0;
6896 if (This->depth_blt_rb) {
6897 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6898 This->depth_blt_rb = 0;
6899 This->depth_blt_rb_w = 0;
6900 This->depth_blt_rb_h = 0;
6904 This->blitter->free_private(iface);
6905 This->frag_pipe->free_private(iface);
6906 This->shader_backend->shader_free_private(iface);
6909 for (i = 0; i < GL_LIMITS(textures); i++) {
6910 /* Textures are recreated below */
6911 glDeleteTextures(1, &This->dummyTextureName[i]);
6912 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
6913 This->dummyTextureName[i] = 0;
6917 while(This->numContexts) {
6918 DestroyContext(This, This->contexts[0]);
6920 HeapFree(GetProcessHeap(), 0, swapchain->context);
6921 swapchain->context = NULL;
6922 swapchain->num_contexts = 0;
6925 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6927 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6929 IWineD3DSurfaceImpl *target;
6931 /* Recreate the primary swapchain's context */
6932 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6933 if(swapchain->backBuffer) {
6934 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
6936 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
6938 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
6939 &swapchain->presentParms);
6940 swapchain->num_contexts = 1;
6942 create_dummy_textures(This);
6944 hr = This->shader_backend->shader_alloc_private(iface);
6946 ERR("Failed to recreate shader private data\n");
6949 hr = This->frag_pipe->alloc_private(iface);
6951 TRACE("Fragment pipeline private data couldn't be allocated\n");
6954 hr = This->blitter->alloc_private(iface);
6956 TRACE("Blitter private data couldn't be allocated\n");
6963 This->blitter->free_private(iface);
6964 This->frag_pipe->free_private(iface);
6965 This->shader_backend->shader_free_private(iface);
6969 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6970 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6971 IWineD3DSwapChainImpl *swapchain;
6973 BOOL DisplayModeChanged = FALSE;
6974 WINED3DDISPLAYMODE mode;
6975 TRACE("(%p)\n", This);
6977 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6979 ERR("Failed to get the first implicit swapchain\n");
6983 if(!is_display_mode_supported(This, pPresentationParameters)) {
6984 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6985 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6986 pPresentationParameters->BackBufferHeight);
6987 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6988 return WINED3DERR_INVALIDCALL;
6991 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6992 * on an existing gl context, so there's no real need for recreation.
6994 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6996 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6998 TRACE("New params:\n");
6999 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7000 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7001 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7002 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7003 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7004 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7005 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7006 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7007 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7008 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7009 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7010 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7011 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7013 /* No special treatment of these parameters. Just store them */
7014 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7015 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7016 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7017 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7019 /* What to do about these? */
7020 if(pPresentationParameters->BackBufferCount != 0 &&
7021 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7022 ERR("Cannot change the back buffer count yet\n");
7024 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7025 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7026 ERR("Cannot change the back buffer format yet\n");
7028 if(pPresentationParameters->hDeviceWindow != NULL &&
7029 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7030 ERR("Cannot change the device window yet\n");
7032 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7035 TRACE("Creating the depth stencil buffer\n");
7037 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
7039 pPresentationParameters->BackBufferWidth,
7040 pPresentationParameters->BackBufferHeight,
7041 pPresentationParameters->AutoDepthStencilFormat,
7042 pPresentationParameters->MultiSampleType,
7043 pPresentationParameters->MultiSampleQuality,
7045 &This->auto_depth_stencil_buffer);
7048 ERR("Failed to create the depth stencil buffer\n");
7049 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7050 return WINED3DERR_INVALIDCALL;
7054 /* Reset the depth stencil */
7055 if (pPresentationParameters->EnableAutoDepthStencil)
7056 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7058 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7060 TRACE("Resetting stateblock\n");
7061 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
7062 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
7064 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7066 if(pPresentationParameters->Windowed) {
7067 mode.Width = swapchain->orig_width;
7068 mode.Height = swapchain->orig_height;
7069 mode.RefreshRate = 0;
7070 mode.Format = swapchain->presentParms.BackBufferFormat;
7072 mode.Width = pPresentationParameters->BackBufferWidth;
7073 mode.Height = pPresentationParameters->BackBufferHeight;
7074 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7075 mode.Format = swapchain->presentParms.BackBufferFormat;
7078 /* Should Width == 800 && Height == 0 set 800x600? */
7079 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7080 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7081 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7085 if(!pPresentationParameters->Windowed) {
7086 DisplayModeChanged = TRUE;
7088 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7089 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7091 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7092 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7093 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7095 if(This->auto_depth_stencil_buffer) {
7096 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7100 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7101 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7102 DisplayModeChanged) {
7104 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7106 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7107 if(swapchain->presentParms.Windowed) {
7108 /* switch from windowed to fs */
7109 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7110 pPresentationParameters->BackBufferWidth,
7111 pPresentationParameters->BackBufferHeight);
7113 /* Fullscreen -> fullscreen mode change */
7114 MoveWindow(swapchain->win_handle, 0, 0,
7115 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7118 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7119 /* Fullscreen -> windowed switch */
7120 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7122 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7123 } else if(!pPresentationParameters->Windowed) {
7124 DWORD style = This->style, exStyle = This->exStyle;
7125 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7126 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7127 * Reset to clear up their mess. Guild Wars also loses the device during that.
7131 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7132 pPresentationParameters->BackBufferWidth,
7133 pPresentationParameters->BackBufferHeight);
7134 This->style = style;
7135 This->exStyle = exStyle;
7138 /* Note: No parent needed for initial internal stateblock */
7139 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
7140 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7141 else TRACE("Created stateblock %p\n", This->stateBlock);
7142 This->updateStateBlock = This->stateBlock;
7143 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
7145 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7147 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7150 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7151 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7153 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7159 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7161 /** FIXME: always true at the moment **/
7162 if(!bEnableDialogs) {
7163 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7169 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7170 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7171 TRACE("(%p) : pParameters %p\n", This, pParameters);
7173 *pParameters = This->createParms;
7177 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7178 IWineD3DSwapChain *swapchain;
7180 TRACE("Relaying to swapchain\n");
7182 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7183 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7184 IWineD3DSwapChain_Release(swapchain);
7189 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7190 IWineD3DSwapChain *swapchain;
7192 TRACE("Relaying to swapchain\n");
7194 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7195 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7196 IWineD3DSwapChain_Release(swapchain);
7202 /** ********************************************************
7203 * Notification functions
7204 ** ********************************************************/
7205 /** This function must be called in the release of a resource when ref == 0,
7206 * the contents of resource must still be correct,
7207 * any handles to other resource held by the caller must be closed
7208 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7209 *****************************************************/
7210 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7212 TRACE("(%p) : Adding resource %p\n", This, resource);
7214 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7217 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7219 TRACE("(%p) : Removing resource %p\n", This, resource);
7221 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7224 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7226 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7229 TRACE("(%p) : resource %p\n", This, resource);
7231 context_resource_released((IWineD3DDevice *)This, resource, type);
7234 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7235 case WINED3DRTYPE_SURFACE: {
7238 if (This->d3d_initialized)
7240 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7241 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7242 This->render_targets[i] = NULL;
7245 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7246 This->stencilBufferTarget = NULL;
7252 case WINED3DRTYPE_TEXTURE:
7253 case WINED3DRTYPE_CUBETEXTURE:
7254 case WINED3DRTYPE_VOLUMETEXTURE:
7255 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7256 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7257 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7258 This->stateBlock->textures[counter] = NULL;
7260 if (This->updateStateBlock != This->stateBlock ){
7261 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7262 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7263 This->updateStateBlock->textures[counter] = NULL;
7268 case WINED3DRTYPE_VOLUME:
7269 /* TODO: nothing really? */
7271 case WINED3DRTYPE_BUFFER:
7274 TRACE("Cleaning up stream pointers\n");
7276 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7277 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7278 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7280 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7281 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7282 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7283 This->updateStateBlock->streamSource[streamNumber] = 0;
7284 /* Set changed flag? */
7287 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) */
7288 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7289 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7290 This->stateBlock->streamSource[streamNumber] = 0;
7295 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7296 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7297 This->updateStateBlock->pIndexData = NULL;
7300 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7301 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7302 This->stateBlock->pIndexData = NULL;
7309 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7314 /* Remove the resource from the resourceStore */
7315 device_resource_remove(This, resource);
7317 TRACE("Resource released\n");
7321 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7323 IWineD3DResourceImpl *resource, *cursor;
7325 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7327 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7328 TRACE("enumerating resource %p\n", resource);
7329 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7330 ret = pCallback((IWineD3DResource *) resource, pData);
7331 if(ret == S_FALSE) {
7332 TRACE("Canceling enumeration\n");
7339 /**********************************************************
7340 * IWineD3DDevice VTbl follows
7341 **********************************************************/
7343 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7345 /*** IUnknown methods ***/
7346 IWineD3DDeviceImpl_QueryInterface,
7347 IWineD3DDeviceImpl_AddRef,
7348 IWineD3DDeviceImpl_Release,
7349 /*** IWineD3DDevice methods ***/
7350 IWineD3DDeviceImpl_GetParent,
7351 /*** Creation methods**/
7352 IWineD3DDeviceImpl_CreateBuffer,
7353 IWineD3DDeviceImpl_CreateVertexBuffer,
7354 IWineD3DDeviceImpl_CreateIndexBuffer,
7355 IWineD3DDeviceImpl_CreateStateBlock,
7356 IWineD3DDeviceImpl_CreateSurface,
7357 IWineD3DDeviceImpl_CreateRendertargetView,
7358 IWineD3DDeviceImpl_CreateTexture,
7359 IWineD3DDeviceImpl_CreateVolumeTexture,
7360 IWineD3DDeviceImpl_CreateVolume,
7361 IWineD3DDeviceImpl_CreateCubeTexture,
7362 IWineD3DDeviceImpl_CreateQuery,
7363 IWineD3DDeviceImpl_CreateSwapChain,
7364 IWineD3DDeviceImpl_CreateVertexDeclaration,
7365 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7366 IWineD3DDeviceImpl_CreateVertexShader,
7367 IWineD3DDeviceImpl_CreatePixelShader,
7368 IWineD3DDeviceImpl_CreatePalette,
7369 /*** Odd functions **/
7370 IWineD3DDeviceImpl_Init3D,
7371 IWineD3DDeviceImpl_InitGDI,
7372 IWineD3DDeviceImpl_Uninit3D,
7373 IWineD3DDeviceImpl_UninitGDI,
7374 IWineD3DDeviceImpl_SetMultithreaded,
7375 IWineD3DDeviceImpl_EvictManagedResources,
7376 IWineD3DDeviceImpl_GetAvailableTextureMem,
7377 IWineD3DDeviceImpl_GetBackBuffer,
7378 IWineD3DDeviceImpl_GetCreationParameters,
7379 IWineD3DDeviceImpl_GetDeviceCaps,
7380 IWineD3DDeviceImpl_GetDirect3D,
7381 IWineD3DDeviceImpl_GetDisplayMode,
7382 IWineD3DDeviceImpl_SetDisplayMode,
7383 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7384 IWineD3DDeviceImpl_GetRasterStatus,
7385 IWineD3DDeviceImpl_GetSwapChain,
7386 IWineD3DDeviceImpl_Reset,
7387 IWineD3DDeviceImpl_SetDialogBoxMode,
7388 IWineD3DDeviceImpl_SetCursorProperties,
7389 IWineD3DDeviceImpl_SetCursorPosition,
7390 IWineD3DDeviceImpl_ShowCursor,
7391 IWineD3DDeviceImpl_TestCooperativeLevel,
7392 /*** Getters and setters **/
7393 IWineD3DDeviceImpl_SetClipPlane,
7394 IWineD3DDeviceImpl_GetClipPlane,
7395 IWineD3DDeviceImpl_SetClipStatus,
7396 IWineD3DDeviceImpl_GetClipStatus,
7397 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7398 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7399 IWineD3DDeviceImpl_SetDepthStencilSurface,
7400 IWineD3DDeviceImpl_GetDepthStencilSurface,
7401 IWineD3DDeviceImpl_SetGammaRamp,
7402 IWineD3DDeviceImpl_GetGammaRamp,
7403 IWineD3DDeviceImpl_SetIndexBuffer,
7404 IWineD3DDeviceImpl_GetIndexBuffer,
7405 IWineD3DDeviceImpl_SetBaseVertexIndex,
7406 IWineD3DDeviceImpl_GetBaseVertexIndex,
7407 IWineD3DDeviceImpl_SetLight,
7408 IWineD3DDeviceImpl_GetLight,
7409 IWineD3DDeviceImpl_SetLightEnable,
7410 IWineD3DDeviceImpl_GetLightEnable,
7411 IWineD3DDeviceImpl_SetMaterial,
7412 IWineD3DDeviceImpl_GetMaterial,
7413 IWineD3DDeviceImpl_SetNPatchMode,
7414 IWineD3DDeviceImpl_GetNPatchMode,
7415 IWineD3DDeviceImpl_SetPaletteEntries,
7416 IWineD3DDeviceImpl_GetPaletteEntries,
7417 IWineD3DDeviceImpl_SetPixelShader,
7418 IWineD3DDeviceImpl_GetPixelShader,
7419 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7420 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7421 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7422 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7423 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7424 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7425 IWineD3DDeviceImpl_SetRenderState,
7426 IWineD3DDeviceImpl_GetRenderState,
7427 IWineD3DDeviceImpl_SetRenderTarget,
7428 IWineD3DDeviceImpl_GetRenderTarget,
7429 IWineD3DDeviceImpl_SetFrontBackBuffers,
7430 IWineD3DDeviceImpl_SetSamplerState,
7431 IWineD3DDeviceImpl_GetSamplerState,
7432 IWineD3DDeviceImpl_SetScissorRect,
7433 IWineD3DDeviceImpl_GetScissorRect,
7434 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7435 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7436 IWineD3DDeviceImpl_SetStreamSource,
7437 IWineD3DDeviceImpl_GetStreamSource,
7438 IWineD3DDeviceImpl_SetStreamSourceFreq,
7439 IWineD3DDeviceImpl_GetStreamSourceFreq,
7440 IWineD3DDeviceImpl_SetTexture,
7441 IWineD3DDeviceImpl_GetTexture,
7442 IWineD3DDeviceImpl_SetTextureStageState,
7443 IWineD3DDeviceImpl_GetTextureStageState,
7444 IWineD3DDeviceImpl_SetTransform,
7445 IWineD3DDeviceImpl_GetTransform,
7446 IWineD3DDeviceImpl_SetVertexDeclaration,
7447 IWineD3DDeviceImpl_GetVertexDeclaration,
7448 IWineD3DDeviceImpl_SetVertexShader,
7449 IWineD3DDeviceImpl_GetVertexShader,
7450 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7451 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7452 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7453 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7454 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7455 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7456 IWineD3DDeviceImpl_SetViewport,
7457 IWineD3DDeviceImpl_GetViewport,
7458 IWineD3DDeviceImpl_MultiplyTransform,
7459 IWineD3DDeviceImpl_ValidateDevice,
7460 IWineD3DDeviceImpl_ProcessVertices,
7461 /*** State block ***/
7462 IWineD3DDeviceImpl_BeginStateBlock,
7463 IWineD3DDeviceImpl_EndStateBlock,
7464 /*** Scene management ***/
7465 IWineD3DDeviceImpl_BeginScene,
7466 IWineD3DDeviceImpl_EndScene,
7467 IWineD3DDeviceImpl_Present,
7468 IWineD3DDeviceImpl_Clear,
7469 IWineD3DDeviceImpl_ClearRendertargetView,
7471 IWineD3DDeviceImpl_SetPrimitiveType,
7472 IWineD3DDeviceImpl_GetPrimitiveType,
7473 IWineD3DDeviceImpl_DrawPrimitive,
7474 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7475 IWineD3DDeviceImpl_DrawPrimitiveUP,
7476 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7477 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7478 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7479 IWineD3DDeviceImpl_DrawRectPatch,
7480 IWineD3DDeviceImpl_DrawTriPatch,
7481 IWineD3DDeviceImpl_DeletePatch,
7482 IWineD3DDeviceImpl_ColorFill,
7483 IWineD3DDeviceImpl_UpdateTexture,
7484 IWineD3DDeviceImpl_UpdateSurface,
7485 IWineD3DDeviceImpl_GetFrontBufferData,
7486 /*** object tracking ***/
7487 IWineD3DDeviceImpl_EnumResources
7490 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7491 WINED3DRS_ALPHABLENDENABLE ,
7492 WINED3DRS_ALPHAFUNC ,
7493 WINED3DRS_ALPHAREF ,
7494 WINED3DRS_ALPHATESTENABLE ,
7496 WINED3DRS_COLORWRITEENABLE ,
7497 WINED3DRS_DESTBLEND ,
7498 WINED3DRS_DITHERENABLE ,
7499 WINED3DRS_FILLMODE ,
7500 WINED3DRS_FOGDENSITY ,
7502 WINED3DRS_FOGSTART ,
7503 WINED3DRS_LASTPIXEL ,
7504 WINED3DRS_SHADEMODE ,
7505 WINED3DRS_SRCBLEND ,
7506 WINED3DRS_STENCILENABLE ,
7507 WINED3DRS_STENCILFAIL ,
7508 WINED3DRS_STENCILFUNC ,
7509 WINED3DRS_STENCILMASK ,
7510 WINED3DRS_STENCILPASS ,
7511 WINED3DRS_STENCILREF ,
7512 WINED3DRS_STENCILWRITEMASK ,
7513 WINED3DRS_STENCILZFAIL ,
7514 WINED3DRS_TEXTUREFACTOR ,
7525 WINED3DRS_ZWRITEENABLE
7528 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7529 WINED3DTSS_ALPHAARG0 ,
7530 WINED3DTSS_ALPHAARG1 ,
7531 WINED3DTSS_ALPHAARG2 ,
7532 WINED3DTSS_ALPHAOP ,
7533 WINED3DTSS_BUMPENVLOFFSET ,
7534 WINED3DTSS_BUMPENVLSCALE ,
7535 WINED3DTSS_BUMPENVMAT00 ,
7536 WINED3DTSS_BUMPENVMAT01 ,
7537 WINED3DTSS_BUMPENVMAT10 ,
7538 WINED3DTSS_BUMPENVMAT11 ,
7539 WINED3DTSS_COLORARG0 ,
7540 WINED3DTSS_COLORARG1 ,
7541 WINED3DTSS_COLORARG2 ,
7542 WINED3DTSS_COLOROP ,
7543 WINED3DTSS_RESULTARG ,
7544 WINED3DTSS_TEXCOORDINDEX ,
7545 WINED3DTSS_TEXTURETRANSFORMFLAGS
7548 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7549 WINED3DSAMP_ADDRESSU ,
7550 WINED3DSAMP_ADDRESSV ,
7551 WINED3DSAMP_ADDRESSW ,
7552 WINED3DSAMP_BORDERCOLOR ,
7553 WINED3DSAMP_MAGFILTER ,
7554 WINED3DSAMP_MINFILTER ,
7555 WINED3DSAMP_MIPFILTER ,
7556 WINED3DSAMP_MIPMAPLODBIAS ,
7557 WINED3DSAMP_MAXMIPLEVEL ,
7558 WINED3DSAMP_MAXANISOTROPY ,
7559 WINED3DSAMP_SRGBTEXTURE ,
7560 WINED3DSAMP_ELEMENTINDEX
7563 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7565 WINED3DRS_AMBIENTMATERIALSOURCE ,
7566 WINED3DRS_CLIPPING ,
7567 WINED3DRS_CLIPPLANEENABLE ,
7568 WINED3DRS_COLORVERTEX ,
7569 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7570 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7571 WINED3DRS_FOGDENSITY ,
7573 WINED3DRS_FOGSTART ,
7574 WINED3DRS_FOGTABLEMODE ,
7575 WINED3DRS_FOGVERTEXMODE ,
7576 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7577 WINED3DRS_LIGHTING ,
7578 WINED3DRS_LOCALVIEWER ,
7579 WINED3DRS_MULTISAMPLEANTIALIAS ,
7580 WINED3DRS_MULTISAMPLEMASK ,
7581 WINED3DRS_NORMALIZENORMALS ,
7582 WINED3DRS_PATCHEDGESTYLE ,
7583 WINED3DRS_POINTSCALE_A ,
7584 WINED3DRS_POINTSCALE_B ,
7585 WINED3DRS_POINTSCALE_C ,
7586 WINED3DRS_POINTSCALEENABLE ,
7587 WINED3DRS_POINTSIZE ,
7588 WINED3DRS_POINTSIZE_MAX ,
7589 WINED3DRS_POINTSIZE_MIN ,
7590 WINED3DRS_POINTSPRITEENABLE ,
7591 WINED3DRS_RANGEFOGENABLE ,
7592 WINED3DRS_SPECULARMATERIALSOURCE ,
7593 WINED3DRS_TWEENFACTOR ,
7594 WINED3DRS_VERTEXBLEND ,
7595 WINED3DRS_CULLMODE ,
7599 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7600 WINED3DTSS_TEXCOORDINDEX ,
7601 WINED3DTSS_TEXTURETRANSFORMFLAGS
7604 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7605 WINED3DSAMP_DMAPOFFSET
7608 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7609 DWORD rep = This->StateTable[state].representative;
7610 struct wined3d_context *context;
7615 for(i = 0; i < This->numContexts; i++) {
7616 context = This->contexts[i];
7617 if(isStateDirty(context, rep)) continue;
7619 context->dirtyArray[context->numDirtyEntries++] = rep;
7622 context->isStateDirty[idx] |= (1 << shift);
7626 void get_drawable_size_pbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7628 IWineD3DDeviceImpl *device = ((IWineD3DSurfaceImpl *)context->current_rt)->resource.wineD3DDevice;
7629 /* The drawable size of a pbuffer render target is the current pbuffer size. */
7630 *width = device->pbufferWidth;
7631 *height = device->pbufferHeight;
7634 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7636 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->current_rt;
7637 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7638 *width = surface->pow2Width;
7639 *height = surface->pow2Height;
7642 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7644 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->surface;
7645 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7646 * current context's drawable, which is the size of the back buffer of the swapchain
7647 * the active context belongs to. The back buffer of the swapchain is stored as the
7648 * surface the context belongs to. */
7649 *width = surface->currentDesc.Width;
7650 *height = surface->currentDesc.Height;