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"
37 WINE_DEFAULT_DEBUG_CHANNEL(d3d
);
38 #define GLINFO_LOCATION This->adapter->gl_info
40 /* Define the default light parameters as specified by MSDN */
41 const WINED3DLIGHT WINED3D_default_light
= {
43 WINED3DLIGHT_DIRECTIONAL
, /* Type */
44 { 1.0f
, 1.0f
, 1.0f
, 0.0f
}, /* Diffuse r,g,b,a */
45 { 0.0f
, 0.0f
, 0.0f
, 0.0f
}, /* Specular r,g,b,a */
46 { 0.0f
, 0.0f
, 0.0f
, 0.0f
}, /* Ambient r,g,b,a, */
47 { 0.0f
, 0.0f
, 0.0f
}, /* Position x,y,z */
48 { 0.0f
, 0.0f
, 1.0f
}, /* Direction x,y,z */
51 0.0f
, 0.0f
, 0.0f
, /* Attenuation 0,1,2 */
56 #define IS_OPTION_TRUE(ch) ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
57 /**********************************************************
58 * Global variable / Constants follow
59 **********************************************************/
60 const float identity
[] =
62 1.0f
, 0.0f
, 0.0f
, 0.0f
,
63 0.0f
, 1.0f
, 0.0f
, 0.0f
,
64 0.0f
, 0.0f
, 1.0f
, 0.0f
,
65 0.0f
, 0.0f
, 0.0f
, 1.0f
,
66 }; /* When needed for comparisons */
68 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
69 * actually have the same values in GL and D3D. */
70 static GLenum
gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type
)
72 switch(primitive_type
)
74 case WINED3DPT_POINTLIST
:
77 case WINED3DPT_LINELIST
:
80 case WINED3DPT_LINESTRIP
:
83 case WINED3DPT_TRIANGLELIST
:
86 case WINED3DPT_TRIANGLESTRIP
:
87 return GL_TRIANGLE_STRIP
;
89 case WINED3DPT_TRIANGLEFAN
:
90 return GL_TRIANGLE_FAN
;
92 case WINED3DPT_LINELIST_ADJ
:
93 return GL_LINES_ADJACENCY_ARB
;
95 case WINED3DPT_LINESTRIP_ADJ
:
96 return GL_LINE_STRIP_ADJACENCY_ARB
;
98 case WINED3DPT_TRIANGLELIST_ADJ
:
99 return GL_TRIANGLES_ADJACENCY_ARB
;
101 case WINED3DPT_TRIANGLESTRIP_ADJ
:
102 return GL_TRIANGLE_STRIP_ADJACENCY_ARB
;
105 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type
));
110 static WINED3DPRIMITIVETYPE
d3d_primitive_type_from_gl(GLenum primitive_type
)
112 switch(primitive_type
)
115 return WINED3DPT_POINTLIST
;
118 return WINED3DPT_LINELIST
;
121 return WINED3DPT_LINESTRIP
;
124 return WINED3DPT_TRIANGLELIST
;
126 case GL_TRIANGLE_STRIP
:
127 return WINED3DPT_TRIANGLESTRIP
;
129 case GL_TRIANGLE_FAN
:
130 return WINED3DPT_TRIANGLEFAN
;
132 case GL_LINES_ADJACENCY_ARB
:
133 return WINED3DPT_LINELIST_ADJ
;
135 case GL_LINE_STRIP_ADJACENCY_ARB
:
136 return WINED3DPT_LINESTRIP_ADJ
;
138 case GL_TRIANGLES_ADJACENCY_ARB
:
139 return WINED3DPT_TRIANGLELIST_ADJ
;
141 case GL_TRIANGLE_STRIP_ADJACENCY_ARB
:
142 return WINED3DPT_TRIANGLESTRIP_ADJ
;
145 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type
));
146 return WINED3DPT_UNDEFINED
;
150 static BOOL
fixed_get_input(BYTE usage
, BYTE usage_idx
, unsigned int *regnum
)
152 if ((usage
== WINED3DDECLUSAGE_POSITION
|| usage
== WINED3DDECLUSAGE_POSITIONT
) && usage_idx
== 0)
153 *regnum
= WINED3D_FFP_POSITION
;
154 else if (usage
== WINED3DDECLUSAGE_BLENDWEIGHT
&& usage_idx
== 0)
155 *regnum
= WINED3D_FFP_BLENDWEIGHT
;
156 else if (usage
== WINED3DDECLUSAGE_BLENDINDICES
&& usage_idx
== 0)
157 *regnum
= WINED3D_FFP_BLENDINDICES
;
158 else if (usage
== WINED3DDECLUSAGE_NORMAL
&& usage_idx
== 0)
159 *regnum
= WINED3D_FFP_NORMAL
;
160 else if (usage
== WINED3DDECLUSAGE_PSIZE
&& usage_idx
== 0)
161 *regnum
= WINED3D_FFP_PSIZE
;
162 else if (usage
== WINED3DDECLUSAGE_COLOR
&& usage_idx
== 0)
163 *regnum
= WINED3D_FFP_DIFFUSE
;
164 else if (usage
== WINED3DDECLUSAGE_COLOR
&& usage_idx
== 1)
165 *regnum
= WINED3D_FFP_SPECULAR
;
166 else if (usage
== WINED3DDECLUSAGE_TEXCOORD
&& usage_idx
< WINED3DDP_MAXTEXCOORD
)
167 *regnum
= WINED3D_FFP_TEXCOORD0
+ usage_idx
;
170 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage
), usage_idx
);
178 /* Context activation is done by the caller. */
179 void device_stream_info_from_declaration(IWineD3DDeviceImpl
*This
,
180 BOOL use_vshader
, struct wined3d_stream_info
*stream_info
, BOOL
*fixup
)
182 /* We need to deal with frequency data! */
183 IWineD3DVertexDeclarationImpl
*declaration
= (IWineD3DVertexDeclarationImpl
*)This
->stateBlock
->vertexDecl
;
184 UINT stream_count
= This
->stateBlock
->streamIsUP
? 0 : declaration
->num_streams
;
185 const DWORD
*streams
= declaration
->streams
;
188 stream_info
->use_map
= 0;
189 stream_info
->swizzle_map
= 0;
191 /* Check for transformed vertices, disable vertex shader if present. */
192 stream_info
->position_transformed
= declaration
->position_transformed
;
193 if (declaration
->position_transformed
) use_vshader
= FALSE
;
195 /* Translate the declaration into strided data. */
196 for (i
= 0; i
< declaration
->element_count
; ++i
)
198 const struct wined3d_vertex_declaration_element
*element
= &declaration
->elements
[i
];
199 GLuint buffer_object
= 0;
200 const BYTE
*data
= NULL
;
205 TRACE("%p Element %p (%u of %u)\n", declaration
->elements
,
206 element
, i
+ 1, declaration
->element_count
);
208 if (!This
->stateBlock
->streamSource
[element
->input_slot
]) continue;
210 stride
= This
->stateBlock
->streamStride
[element
->input_slot
];
211 if (This
->stateBlock
->streamIsUP
)
213 TRACE("Stream %u is UP, %p\n", element
->input_slot
, This
->stateBlock
->streamSource
[element
->input_slot
]);
215 data
= (BYTE
*)This
->stateBlock
->streamSource
[element
->input_slot
];
219 TRACE("Stream %u isn't UP, %p\n", element
->input_slot
, This
->stateBlock
->streamSource
[element
->input_slot
]);
220 data
= buffer_get_memory(This
->stateBlock
->streamSource
[element
->input_slot
], 0, &buffer_object
);
222 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
223 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
224 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
225 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
226 * not, drawStridedSlow is needed, including a vertex buffer path. */
227 if (This
->stateBlock
->loadBaseVertexIndex
< 0)
229 WARN("loadBaseVertexIndex is < 0 (%d), not using vbos\n", This
->stateBlock
->loadBaseVertexIndex
);
231 data
= buffer_get_sysmem((struct wined3d_buffer
*)This
->stateBlock
->streamSource
[element
->input_slot
]);
232 if ((UINT_PTR
)data
< -This
->stateBlock
->loadBaseVertexIndex
* stride
)
234 FIXME("System memory vertex data load offset is negative!\n");
240 if (buffer_object
) *fixup
= TRUE
;
241 else if (*fixup
&& !use_vshader
242 && (element
->usage
== WINED3DDECLUSAGE_COLOR
243 || element
->usage
== WINED3DDECLUSAGE_POSITIONT
))
245 static BOOL warned
= FALSE
;
248 /* This may be bad with the fixed function pipeline. */
249 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
255 data
+= element
->offset
;
257 TRACE("offset %u input_slot %u usage_idx %d\n", element
->offset
, element
->input_slot
, element
->usage_idx
);
261 if (element
->output_slot
== ~0U)
263 /* TODO: Assuming vertexdeclarations are usually used with the
264 * same or a similar shader, it might be worth it to store the
265 * last used output slot and try that one first. */
266 stride_used
= vshader_get_input(This
->stateBlock
->vertexShader
,
267 element
->usage
, element
->usage_idx
, &idx
);
271 idx
= element
->output_slot
;
277 if (!element
->ffp_valid
)
279 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
280 debug_d3dformat(element
->format_desc
->format
), debug_d3ddeclusage(element
->usage
));
285 stride_used
= fixed_get_input(element
->usage
, element
->usage_idx
, &idx
);
291 TRACE("Load %s array %u [usage %s, usage_idx %u, "
292 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
293 use_vshader
? "shader": "fixed function", idx
,
294 debug_d3ddeclusage(element
->usage
), element
->usage_idx
, element
->input_slot
,
295 element
->offset
, stride
, debug_d3dformat(element
->format_desc
->format
), buffer_object
);
297 stream_info
->elements
[idx
].format_desc
= element
->format_desc
;
298 stream_info
->elements
[idx
].stride
= stride
;
299 stream_info
->elements
[idx
].data
= data
;
300 stream_info
->elements
[idx
].stream_idx
= element
->input_slot
;
301 stream_info
->elements
[idx
].buffer_object
= buffer_object
;
303 if (!This
->adapter
->gl_info
.supported
[EXT_VERTEX_ARRAY_BGRA
]
304 && element
->format_desc
->format
== WINED3DFMT_B8G8R8A8_UNORM
)
306 stream_info
->swizzle_map
|= 1 << idx
;
308 stream_info
->use_map
|= 1 << idx
;
312 /* Now call PreLoad on all the vertex buffers. In the very rare case
313 * that the buffers stopps converting PreLoad will dirtify the VDECL again.
314 * The vertex buffer can now use the strided structure in the device instead of finding its
317 * NULL streams won't be recorded in the array, UP streams won't be either. A stream is only
319 for (i
= 0; i
< stream_count
; ++i
)
321 IWineD3DBuffer
*vb
= This
->stateBlock
->streamSource
[streams
[i
]];
322 if (vb
) IWineD3DBuffer_PreLoad(vb
);
326 static void stream_info_element_from_strided(const struct wined3d_gl_info
*gl_info
,
327 const struct WineDirect3DStridedData
*strided
, struct wined3d_stream_info_element
*e
)
329 const struct GlPixelFormatDesc
*format_desc
= getFormatDescEntry(strided
->format
, gl_info
);
330 e
->format_desc
= format_desc
;
331 e
->stride
= strided
->dwStride
;
332 e
->data
= strided
->lpData
;
334 e
->buffer_object
= 0;
337 void device_stream_info_from_strided(const struct wined3d_gl_info
*gl_info
,
338 const struct WineDirect3DVertexStridedData
*strided
, struct wined3d_stream_info
*stream_info
)
342 memset(stream_info
, 0, sizeof(*stream_info
));
344 if (strided
->position
.lpData
)
345 stream_info_element_from_strided(gl_info
, &strided
->position
, &stream_info
->elements
[WINED3D_FFP_POSITION
]);
346 if (strided
->normal
.lpData
)
347 stream_info_element_from_strided(gl_info
, &strided
->normal
, &stream_info
->elements
[WINED3D_FFP_NORMAL
]);
348 if (strided
->diffuse
.lpData
)
349 stream_info_element_from_strided(gl_info
, &strided
->diffuse
, &stream_info
->elements
[WINED3D_FFP_DIFFUSE
]);
350 if (strided
->specular
.lpData
)
351 stream_info_element_from_strided(gl_info
, &strided
->specular
, &stream_info
->elements
[WINED3D_FFP_SPECULAR
]);
353 for (i
= 0; i
< WINED3DDP_MAXTEXCOORD
; ++i
)
355 if (strided
->texCoords
[i
].lpData
)
356 stream_info_element_from_strided(gl_info
, &strided
->texCoords
[i
],
357 &stream_info
->elements
[WINED3D_FFP_TEXCOORD0
+ i
]);
360 stream_info
->position_transformed
= strided
->position_transformed
;
362 for (i
= 0; i
< sizeof(stream_info
->elements
) / sizeof(*stream_info
->elements
); ++i
)
364 if (!stream_info
->elements
[i
].format_desc
) continue;
366 if (!gl_info
->supported
[EXT_VERTEX_ARRAY_BGRA
]
367 && stream_info
->elements
[i
].format_desc
->format
== WINED3DFMT_B8G8R8A8_UNORM
)
369 stream_info
->swizzle_map
|= 1 << i
;
371 stream_info
->use_map
|= 1 << i
;
375 /**********************************************************
376 * IUnknown parts follows
377 **********************************************************/
379 static HRESULT WINAPI
IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice
*iface
,REFIID riid
,LPVOID
*ppobj
)
381 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
383 TRACE("(%p)->(%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
384 if (IsEqualGUID(riid
, &IID_IUnknown
)
385 || IsEqualGUID(riid
, &IID_IWineD3DBase
)
386 || IsEqualGUID(riid
, &IID_IWineD3DDevice
)) {
387 IUnknown_AddRef(iface
);
392 return E_NOINTERFACE
;
395 static ULONG WINAPI
IWineD3DDeviceImpl_AddRef(IWineD3DDevice
*iface
) {
396 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
397 ULONG refCount
= InterlockedIncrement(&This
->ref
);
399 TRACE("(%p) : AddRef increasing from %d\n", This
, refCount
- 1);
403 static ULONG WINAPI
IWineD3DDeviceImpl_Release(IWineD3DDevice
*iface
) {
404 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
405 ULONG refCount
= InterlockedDecrement(&This
->ref
);
407 TRACE("(%p) : Releasing from %d\n", This
, refCount
+ 1);
412 for (i
= 0; i
< sizeof(This
->multistate_funcs
)/sizeof(This
->multistate_funcs
[0]); ++i
) {
413 HeapFree(GetProcessHeap(), 0, This
->multistate_funcs
[i
]);
414 This
->multistate_funcs
[i
] = NULL
;
417 /* TODO: Clean up all the surfaces and textures! */
418 /* NOTE: You must release the parent if the object was created via a callback
419 ** ***************************/
421 if (!list_empty(&This
->resources
)) {
422 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This
);
423 dumpResources(&This
->resources
);
426 if(This
->contexts
) ERR("Context array not freed!\n");
427 if (This
->hardwareCursor
) DestroyCursor(This
->hardwareCursor
);
428 This
->haveHardwareCursor
= FALSE
;
430 IWineD3D_Release(This
->wined3d
);
431 This
->wined3d
= NULL
;
432 HeapFree(GetProcessHeap(), 0, This
);
433 TRACE("Freed device %p\n", This
);
439 /**********************************************************
440 * IWineD3DDevice implementation follows
441 **********************************************************/
442 static HRESULT WINAPI
IWineD3DDeviceImpl_GetParent(IWineD3DDevice
*iface
, IUnknown
**pParent
) {
443 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
444 *pParent
= This
->parent
;
445 IUnknown_AddRef(This
->parent
);
449 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice
*iface
, struct wined3d_buffer_desc
*desc
,
450 const void *data
, IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
, IWineD3DBuffer
**buffer
)
452 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
453 struct wined3d_buffer
*object
;
456 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface
, desc
, data
, parent
, buffer
);
458 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
461 ERR("Failed to allocate memory\n");
462 return E_OUTOFMEMORY
;
465 FIXME("Ignoring access flags (pool)\n");
467 hr
= buffer_init(object
, This
, desc
->byte_width
, desc
->usage
, WINED3DFMT_UNKNOWN
,
468 WINED3DPOOL_MANAGED
, GL_ARRAY_BUFFER_ARB
, data
, parent
, parent_ops
);
471 WARN("Failed to initialize buffer, hr %#x.\n", hr
);
472 HeapFree(GetProcessHeap(), 0, object
);
475 object
->desc
= *desc
;
477 TRACE("Created buffer %p.\n", object
);
479 *buffer
= (IWineD3DBuffer
*)object
;
484 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice
*iface
,
485 UINT Size
, DWORD Usage
, WINED3DPOOL Pool
, IWineD3DBuffer
**ppVertexBuffer
,
486 IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
)
488 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
489 struct wined3d_buffer
*object
;
492 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
493 iface
, Size
, Usage
, Pool
, ppVertexBuffer
, parent
, parent_ops
);
495 if (Pool
== WINED3DPOOL_SCRATCH
)
497 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
498 * anyway, SCRATCH vertex buffers aren't usable anywhere
500 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
501 *ppVertexBuffer
= NULL
;
502 return WINED3DERR_INVALIDCALL
;
505 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
508 ERR("Out of memory\n");
509 *ppVertexBuffer
= NULL
;
510 return WINED3DERR_OUTOFVIDEOMEMORY
;
513 hr
= buffer_init(object
, This
, Size
, Usage
, WINED3DFMT_VERTEXDATA
,
514 Pool
, GL_ARRAY_BUFFER_ARB
, NULL
, parent
, parent_ops
);
517 WARN("Failed to initialize buffer, hr %#x.\n", hr
);
518 HeapFree(GetProcessHeap(), 0, object
);
522 TRACE("Created buffer %p.\n", object
);
523 *ppVertexBuffer
= (IWineD3DBuffer
*)object
;
528 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice
*iface
,
529 UINT Length
, DWORD Usage
, WINED3DPOOL Pool
, IWineD3DBuffer
**ppIndexBuffer
,
530 IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
)
532 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
533 struct wined3d_buffer
*object
;
536 TRACE("(%p) Creating index buffer\n", This
);
538 /* Allocate the storage for the device */
539 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
542 ERR("Out of memory\n");
543 *ppIndexBuffer
= NULL
;
544 return WINED3DERR_OUTOFVIDEOMEMORY
;
547 hr
= buffer_init(object
, This
, Length
, Usage
| WINED3DUSAGE_STATICDECL
,
548 WINED3DFMT_UNKNOWN
, Pool
, GL_ELEMENT_ARRAY_BUFFER_ARB
, NULL
,
552 WARN("Failed to initialize buffer, hr %#x\n", hr
);
553 HeapFree(GetProcessHeap(), 0, object
);
557 TRACE("Created buffer %p.\n", object
);
559 *ppIndexBuffer
= (IWineD3DBuffer
*) object
;
564 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice
*iface
,
565 WINED3DSTATEBLOCKTYPE type
, IWineD3DStateBlock
**stateblock
, IUnknown
*parent
)
567 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
568 IWineD3DStateBlockImpl
*object
;
571 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
574 ERR("Failed to allocate stateblock memory.\n");
575 return E_OUTOFMEMORY
;
578 hr
= stateblock_init(object
, This
, type
);
581 WARN("Failed to initialize stateblock, hr %#x.\n", hr
);
582 HeapFree(GetProcessHeap(), 0, object
);
586 TRACE("Created stateblock %p.\n", object
);
587 *stateblock
= (IWineD3DStateBlock
*)object
;
592 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice
*iface
, UINT Width
, UINT Height
,
593 WINED3DFORMAT Format
, BOOL Lockable
, BOOL Discard
, UINT Level
, IWineD3DSurface
**ppSurface
,
594 DWORD Usage
, WINED3DPOOL Pool
, WINED3DMULTISAMPLE_TYPE MultiSample
, DWORD MultisampleQuality
,
595 WINED3DSURFTYPE Impl
, IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
)
597 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
598 IWineD3DSurfaceImpl
*object
;
601 TRACE("(%p) Create surface\n",This
);
603 if (Impl
== SURFACE_OPENGL
&& !This
->adapter
)
605 ERR("OpenGL surfaces are not available without OpenGL.\n");
606 return WINED3DERR_NOTAVAILABLE
;
609 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
612 ERR("Failed to allocate surface memory.\n");
613 return WINED3DERR_OUTOFVIDEOMEMORY
;
616 hr
= surface_init(object
, Impl
, This
->surface_alignment
, Width
, Height
, Level
, Lockable
,
617 Discard
, MultiSample
, MultisampleQuality
, This
, Usage
, Format
, Pool
, parent
, parent_ops
);
620 WARN("Failed to initialize surface, returning %#x.\n", hr
);
621 HeapFree(GetProcessHeap(), 0, object
);
625 TRACE("(%p) : Created surface %p\n", This
, object
);
627 *ppSurface
= (IWineD3DSurface
*)object
;
632 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice
*iface
,
633 IWineD3DResource
*resource
, IUnknown
*parent
, IWineD3DRendertargetView
**rendertarget_view
)
635 struct wined3d_rendertarget_view
*object
;
637 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
640 ERR("Failed to allocate memory\n");
641 return E_OUTOFMEMORY
;
644 object
->vtbl
= &wined3d_rendertarget_view_vtbl
;
645 object
->refcount
= 1;
646 IWineD3DResource_AddRef(resource
);
647 object
->resource
= resource
;
648 object
->parent
= parent
;
650 *rendertarget_view
= (IWineD3DRendertargetView
*)object
;
655 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice
*iface
,
656 UINT Width
, UINT Height
, UINT Levels
, DWORD Usage
, WINED3DFORMAT Format
, WINED3DPOOL Pool
,
657 IWineD3DTexture
**ppTexture
, IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
)
659 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
660 IWineD3DTextureImpl
*object
;
663 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This
, Width
, Height
, Levels
, Usage
);
664 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
665 Format
, debug_d3dformat(Format
), Pool
, ppTexture
, parent
);
667 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
670 ERR("Out of memory\n");
672 return WINED3DERR_OUTOFVIDEOMEMORY
;
675 hr
= texture_init(object
, Width
, Height
, Levels
, This
, Usage
, Format
, Pool
, parent
, parent_ops
);
678 WARN("Failed to initialize texture, returning %#x\n", hr
);
679 HeapFree(GetProcessHeap(), 0, object
);
684 *ppTexture
= (IWineD3DTexture
*)object
;
686 TRACE("(%p) : Created texture %p\n", This
, object
);
691 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice
*iface
,
692 UINT Width
, UINT Height
, UINT Depth
, UINT Levels
, DWORD Usage
, WINED3DFORMAT Format
, WINED3DPOOL Pool
,
693 IWineD3DVolumeTexture
**ppVolumeTexture
, IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
)
695 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
696 IWineD3DVolumeTextureImpl
*object
;
699 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
700 Depth
, Levels
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
702 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
705 ERR("Out of memory\n");
706 *ppVolumeTexture
= NULL
;
707 return WINED3DERR_OUTOFVIDEOMEMORY
;
710 hr
= volumetexture_init(object
, Width
, Height
, Depth
, Levels
, This
, Usage
, Format
, Pool
, parent
, parent_ops
);
713 WARN("Failed to initialize volumetexture, returning %#x\n", hr
);
714 HeapFree(GetProcessHeap(), 0, object
);
715 *ppVolumeTexture
= NULL
;
719 TRACE("(%p) : Created volume texture %p.\n", This
, object
);
720 *ppVolumeTexture
= (IWineD3DVolumeTexture
*)object
;
725 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice
*iface
, UINT Width
, UINT Height
,
726 UINT Depth
, DWORD Usage
, WINED3DFORMAT Format
, WINED3DPOOL Pool
, IWineD3DVolume
**ppVolume
,
727 IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
)
729 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
730 IWineD3DVolumeImpl
*object
;
733 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
734 Depth
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
736 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
739 ERR("Out of memory\n");
741 return WINED3DERR_OUTOFVIDEOMEMORY
;
744 hr
= volume_init(object
, This
, Width
, Height
, Depth
, Usage
, Format
, Pool
, parent
, parent_ops
);
747 WARN("Failed to initialize volume, returning %#x.\n", hr
);
748 HeapFree(GetProcessHeap(), 0, object
);
752 TRACE("(%p) : Created volume %p.\n", This
, object
);
753 *ppVolume
= (IWineD3DVolume
*)object
;
758 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice
*iface
, UINT EdgeLength
, UINT Levels
,
759 DWORD Usage
, WINED3DFORMAT Format
, WINED3DPOOL Pool
, IWineD3DCubeTexture
**ppCubeTexture
,
760 IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
)
762 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
763 IWineD3DCubeTextureImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
766 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
769 ERR("Out of memory\n");
770 *ppCubeTexture
= NULL
;
771 return WINED3DERR_OUTOFVIDEOMEMORY
;
774 hr
= cubetexture_init(object
, EdgeLength
, Levels
, This
, Usage
, Format
, Pool
, parent
, parent_ops
);
777 WARN("Failed to initialize cubetexture, returning %#x\n", hr
);
778 HeapFree(GetProcessHeap(), 0, object
);
779 *ppCubeTexture
= NULL
;
783 TRACE("(%p) : Created Cube Texture %p\n", This
, object
);
784 *ppCubeTexture
= (IWineD3DCubeTexture
*)object
;
789 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice
*iface
, WINED3DQUERYTYPE Type
, IWineD3DQuery
**ppQuery
, IUnknown
* parent
) {
790 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
791 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
792 IWineD3DQueryImpl
*object
; /*NOTE: impl ref allowed since this is a create function */
793 HRESULT hr
= WINED3DERR_NOTAVAILABLE
;
794 const IWineD3DQueryVtbl
*vtable
;
796 /* Just a check to see if we support this type of query */
798 case WINED3DQUERYTYPE_OCCLUSION
:
799 TRACE("(%p) occlusion query\n", This
);
800 if (gl_info
->supported
[ARB_OCCLUSION_QUERY
])
803 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
805 vtable
= &IWineD3DOcclusionQuery_Vtbl
;
808 case WINED3DQUERYTYPE_EVENT
:
809 if (!gl_info
->supported
[NV_FENCE
] && !gl_info
->supported
[APPLE_FENCE
])
811 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
812 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
814 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This
);
816 vtable
= &IWineD3DEventQuery_Vtbl
;
820 case WINED3DQUERYTYPE_VCACHE
:
821 case WINED3DQUERYTYPE_RESOURCEMANAGER
:
822 case WINED3DQUERYTYPE_VERTEXSTATS
:
823 case WINED3DQUERYTYPE_TIMESTAMP
:
824 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT
:
825 case WINED3DQUERYTYPE_TIMESTAMPFREQ
:
826 case WINED3DQUERYTYPE_PIPELINETIMINGS
:
827 case WINED3DQUERYTYPE_INTERFACETIMINGS
:
828 case WINED3DQUERYTYPE_VERTEXTIMINGS
:
829 case WINED3DQUERYTYPE_PIXELTIMINGS
:
830 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS
:
831 case WINED3DQUERYTYPE_CACHEUTILIZATION
:
833 /* Use the base Query vtable until we have a special one for each query */
834 vtable
= &IWineD3DQuery_Vtbl
;
835 FIXME("(%p) Unhandled query type %d\n", This
, Type
);
837 if(NULL
== ppQuery
|| hr
!= WINED3D_OK
) {
841 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
844 ERR("Out of memory\n");
846 return WINED3DERR_OUTOFVIDEOMEMORY
;
849 object
->lpVtbl
= vtable
;
851 object
->state
= QUERY_CREATED
;
852 object
->device
= This
;
853 object
->parent
= parent
;
856 *ppQuery
= (IWineD3DQuery
*)object
;
858 /* allocated the 'extended' data based on the type of query requested */
860 case WINED3DQUERYTYPE_OCCLUSION
:
861 object
->extendedData
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_occlusion_query
));
862 ((struct wined3d_occlusion_query
*)object
->extendedData
)->context
= NULL
;
865 case WINED3DQUERYTYPE_EVENT
:
866 object
->extendedData
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_event_query
));
867 ((struct wined3d_event_query
*)object
->extendedData
)->context
= NULL
;
870 case WINED3DQUERYTYPE_VCACHE
:
871 case WINED3DQUERYTYPE_RESOURCEMANAGER
:
872 case WINED3DQUERYTYPE_VERTEXSTATS
:
873 case WINED3DQUERYTYPE_TIMESTAMP
:
874 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT
:
875 case WINED3DQUERYTYPE_TIMESTAMPFREQ
:
876 case WINED3DQUERYTYPE_PIPELINETIMINGS
:
877 case WINED3DQUERYTYPE_INTERFACETIMINGS
:
878 case WINED3DQUERYTYPE_VERTEXTIMINGS
:
879 case WINED3DQUERYTYPE_PIXELTIMINGS
:
880 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS
:
881 case WINED3DQUERYTYPE_CACHEUTILIZATION
:
883 object
->extendedData
= 0;
884 FIXME("(%p) Unhandled query type %d\n",This
, Type
);
886 TRACE("(%p) : Created Query %p\n", This
, object
);
890 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice
*iface
,
891 WINED3DPRESENT_PARAMETERS
*present_parameters
, IWineD3DSwapChain
**swapchain
,
892 IUnknown
*parent
, WINED3DSURFTYPE surface_type
)
894 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
895 IWineD3DSwapChainImpl
*object
;
898 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
899 iface
, present_parameters
, swapchain
, parent
, surface_type
);
901 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
904 ERR("Failed to allocate swapchain memory.\n");
905 return E_OUTOFMEMORY
;
908 hr
= swapchain_init(object
, surface_type
, This
, present_parameters
, parent
);
911 WARN("Failed to initialize swapchain, hr %#x.\n", hr
);
912 HeapFree(GetProcessHeap(), 0, object
);
916 TRACE("Created swapchain %p.\n", object
);
917 *swapchain
= (IWineD3DSwapChain
*)object
;
922 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
923 static UINT WINAPI
IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice
*iface
) {
924 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
925 TRACE("(%p)\n", This
);
927 return This
->NumberOfSwapChains
;
930 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice
*iface
, UINT iSwapChain
, IWineD3DSwapChain
**pSwapChain
) {
931 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
932 TRACE("(%p) : swapchain %d\n", This
, iSwapChain
);
934 if(iSwapChain
< This
->NumberOfSwapChains
) {
935 *pSwapChain
= This
->swapchains
[iSwapChain
];
936 IWineD3DSwapChain_AddRef(*pSwapChain
);
937 TRACE("(%p) returning %p\n", This
, *pSwapChain
);
940 TRACE("Swapchain out of range\n");
942 return WINED3DERR_INVALIDCALL
;
946 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice
*iface
,
947 IWineD3DVertexDeclaration
**declaration
, IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
,
948 const WINED3DVERTEXELEMENT
*elements
, UINT element_count
)
950 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
951 IWineD3DVertexDeclarationImpl
*object
= NULL
;
954 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
955 iface
, declaration
, parent
, elements
, element_count
);
957 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
960 ERR("Failed to allocate vertex declaration memory.\n");
961 return E_OUTOFMEMORY
;
964 hr
= vertexdeclaration_init(object
, This
, elements
, element_count
, parent
, parent_ops
);
967 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr
);
968 HeapFree(GetProcessHeap(), 0, object
);
972 TRACE("Created vertex declaration %p.\n", object
);
973 *declaration
= (IWineD3DVertexDeclaration
*)object
;
978 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl
*This
, /* For the GL info, which has the type table */
979 DWORD fvf
, WINED3DVERTEXELEMENT
** ppVertexElements
) {
981 unsigned int idx
, idx2
;
983 BOOL has_pos
= (fvf
& WINED3DFVF_POSITION_MASK
) != 0;
984 BOOL has_blend
= (fvf
& WINED3DFVF_XYZB5
) > WINED3DFVF_XYZRHW
;
985 BOOL has_blend_idx
= has_blend
&&
986 (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB5
) ||
987 (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
) ||
988 (fvf
& WINED3DFVF_LASTBETA_UBYTE4
));
989 BOOL has_normal
= (fvf
& WINED3DFVF_NORMAL
) != 0;
990 BOOL has_psize
= (fvf
& WINED3DFVF_PSIZE
) != 0;
991 BOOL has_diffuse
= (fvf
& WINED3DFVF_DIFFUSE
) != 0;
992 BOOL has_specular
= (fvf
& WINED3DFVF_SPECULAR
) !=0;
994 DWORD num_textures
= (fvf
& WINED3DFVF_TEXCOUNT_MASK
) >> WINED3DFVF_TEXCOUNT_SHIFT
;
995 DWORD texcoords
= (fvf
& 0xFFFF0000) >> 16;
996 WINED3DVERTEXELEMENT
*elements
= NULL
;
999 DWORD num_blends
= 1 + (((fvf
& WINED3DFVF_XYZB5
) - WINED3DFVF_XYZB1
) >> 1);
1000 if (has_blend_idx
) num_blends
--;
1002 /* Compute declaration size */
1003 size
= has_pos
+ (has_blend
&& num_blends
> 0) + has_blend_idx
+ has_normal
+
1004 has_psize
+ has_diffuse
+ has_specular
+ num_textures
;
1006 /* convert the declaration */
1007 elements
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WINED3DVERTEXELEMENT
));
1008 if (!elements
) return ~0U;
1012 if (!has_blend
&& (fvf
& WINED3DFVF_XYZRHW
)) {
1013 elements
[idx
].format
= WINED3DFMT_R32G32B32A32_FLOAT
;
1014 elements
[idx
].usage
= WINED3DDECLUSAGE_POSITIONT
;
1016 else if ((fvf
& WINED3DFVF_XYZW
) == WINED3DFVF_XYZW
) {
1017 elements
[idx
].format
= WINED3DFMT_R32G32B32A32_FLOAT
;
1018 elements
[idx
].usage
= WINED3DDECLUSAGE_POSITION
;
1021 elements
[idx
].format
= WINED3DFMT_R32G32B32_FLOAT
;
1022 elements
[idx
].usage
= WINED3DDECLUSAGE_POSITION
;
1024 elements
[idx
].usage_idx
= 0;
1027 if (has_blend
&& (num_blends
> 0)) {
1028 if (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB2
) && (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
))
1029 elements
[idx
].format
= WINED3DFMT_B8G8R8A8_UNORM
;
1031 switch(num_blends
) {
1032 case 1: elements
[idx
].format
= WINED3DFMT_R32_FLOAT
; break;
1033 case 2: elements
[idx
].format
= WINED3DFMT_R32G32_FLOAT
; break;
1034 case 3: elements
[idx
].format
= WINED3DFMT_R32G32B32_FLOAT
; break;
1035 case 4: elements
[idx
].format
= WINED3DFMT_R32G32B32A32_FLOAT
; break;
1037 ERR("Unexpected amount of blend values: %u\n", num_blends
);
1040 elements
[idx
].usage
= WINED3DDECLUSAGE_BLENDWEIGHT
;
1041 elements
[idx
].usage_idx
= 0;
1044 if (has_blend_idx
) {
1045 if (fvf
& WINED3DFVF_LASTBETA_UBYTE4
||
1046 (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB2
) && (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
)))
1047 elements
[idx
].format
= WINED3DFMT_R8G8B8A8_UINT
;
1048 else if (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
)
1049 elements
[idx
].format
= WINED3DFMT_B8G8R8A8_UNORM
;
1051 elements
[idx
].format
= WINED3DFMT_R32_FLOAT
;
1052 elements
[idx
].usage
= WINED3DDECLUSAGE_BLENDINDICES
;
1053 elements
[idx
].usage_idx
= 0;
1057 elements
[idx
].format
= WINED3DFMT_R32G32B32_FLOAT
;
1058 elements
[idx
].usage
= WINED3DDECLUSAGE_NORMAL
;
1059 elements
[idx
].usage_idx
= 0;
1063 elements
[idx
].format
= WINED3DFMT_R32_FLOAT
;
1064 elements
[idx
].usage
= WINED3DDECLUSAGE_PSIZE
;
1065 elements
[idx
].usage_idx
= 0;
1069 elements
[idx
].format
= WINED3DFMT_B8G8R8A8_UNORM
;
1070 elements
[idx
].usage
= WINED3DDECLUSAGE_COLOR
;
1071 elements
[idx
].usage_idx
= 0;
1075 elements
[idx
].format
= WINED3DFMT_B8G8R8A8_UNORM
;
1076 elements
[idx
].usage
= WINED3DDECLUSAGE_COLOR
;
1077 elements
[idx
].usage_idx
= 1;
1080 for (idx2
= 0; idx2
< num_textures
; idx2
++) {
1081 unsigned int numcoords
= (texcoords
>> (idx2
*2)) & 0x03;
1082 switch (numcoords
) {
1083 case WINED3DFVF_TEXTUREFORMAT1
:
1084 elements
[idx
].format
= WINED3DFMT_R32_FLOAT
;
1086 case WINED3DFVF_TEXTUREFORMAT2
:
1087 elements
[idx
].format
= WINED3DFMT_R32G32_FLOAT
;
1089 case WINED3DFVF_TEXTUREFORMAT3
:
1090 elements
[idx
].format
= WINED3DFMT_R32G32B32_FLOAT
;
1092 case WINED3DFVF_TEXTUREFORMAT4
:
1093 elements
[idx
].format
= WINED3DFMT_R32G32B32A32_FLOAT
;
1096 elements
[idx
].usage
= WINED3DDECLUSAGE_TEXCOORD
;
1097 elements
[idx
].usage_idx
= idx2
;
1101 /* Now compute offsets, and initialize the rest of the fields */
1102 for (idx
= 0, offset
= 0; idx
< size
; ++idx
)
1104 const struct GlPixelFormatDesc
*format_desc
= getFormatDescEntry(elements
[idx
].format
, &This
->adapter
->gl_info
);
1105 elements
[idx
].input_slot
= 0;
1106 elements
[idx
].method
= WINED3DDECLMETHOD_DEFAULT
;
1107 elements
[idx
].offset
= offset
;
1108 offset
+= format_desc
->component_count
* format_desc
->component_size
;
1111 *ppVertexElements
= elements
;
1115 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice
*iface
,
1116 IWineD3DVertexDeclaration
**declaration
, IUnknown
*parent
,
1117 const struct wined3d_parent_ops
*parent_ops
, DWORD fvf
)
1119 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1120 WINED3DVERTEXELEMENT
*elements
;
1124 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface
, declaration
, parent
, fvf
);
1126 size
= ConvertFvfToDeclaration(This
, fvf
, &elements
);
1127 if (size
== ~0U) return E_OUTOFMEMORY
;
1129 hr
= IWineD3DDevice_CreateVertexDeclaration(iface
, declaration
, parent
, parent_ops
, elements
, size
);
1130 HeapFree(GetProcessHeap(), 0, elements
);
1134 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice
*iface
,
1135 const DWORD
*pFunction
, const struct wined3d_shader_signature
*output_signature
,
1136 IWineD3DVertexShader
**ppVertexShader
, IUnknown
*parent
,
1137 const struct wined3d_parent_ops
*parent_ops
)
1139 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1140 IWineD3DVertexShaderImpl
*object
;
1143 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1146 ERR("Failed to allocate shader memory.\n");
1147 return E_OUTOFMEMORY
;
1150 hr
= vertexshader_init(object
, This
, pFunction
, output_signature
, parent
, parent_ops
);
1153 WARN("Failed to initialize vertex shader, hr %#x.\n", hr
);
1154 HeapFree(GetProcessHeap(), 0, object
);
1158 TRACE("Created vertex shader %p.\n", object
);
1159 *ppVertexShader
= (IWineD3DVertexShader
*)object
;
1164 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice
*iface
,
1165 const DWORD
*byte_code
, const struct wined3d_shader_signature
*output_signature
,
1166 IWineD3DGeometryShader
**shader
, IUnknown
*parent
,
1167 const struct wined3d_parent_ops
*parent_ops
)
1169 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1170 struct wined3d_geometryshader
*object
;
1173 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1176 ERR("Failed to allocate shader memory.\n");
1177 return E_OUTOFMEMORY
;
1180 hr
= geometryshader_init(object
, This
, byte_code
, output_signature
, parent
, parent_ops
);
1183 WARN("Failed to initialize geometry shader, hr %#x.\n", hr
);
1184 HeapFree(GetProcessHeap(), 0, object
);
1188 TRACE("Created geometry shader %p.\n", object
);
1189 *shader
= (IWineD3DGeometryShader
*)object
;
1194 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice
*iface
,
1195 const DWORD
*pFunction
, const struct wined3d_shader_signature
*output_signature
,
1196 IWineD3DPixelShader
**ppPixelShader
, IUnknown
*parent
,
1197 const struct wined3d_parent_ops
*parent_ops
)
1199 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1200 IWineD3DPixelShaderImpl
*object
;
1203 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1206 ERR("Failed to allocate shader memory.\n");
1207 return E_OUTOFMEMORY
;
1210 hr
= pixelshader_init(object
, This
, pFunction
, output_signature
, parent
, parent_ops
);
1213 WARN("Failed to initialize pixel shader, hr %#x.\n", hr
);
1214 HeapFree(GetProcessHeap(), 0, object
);
1218 TRACE("Created pixel shader %p.\n", object
);
1219 *ppPixelShader
= (IWineD3DPixelShader
*)object
;
1224 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice
*iface
, DWORD Flags
,
1225 const PALETTEENTRY
*PalEnt
, IWineD3DPalette
**Palette
, IUnknown
*Parent
)
1227 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1228 IWineD3DPaletteImpl
*object
;
1230 TRACE("(%p)->(%x, %p, %p, %p)\n", This
, Flags
, PalEnt
, Palette
, Parent
);
1232 /* Create the new object */
1233 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DPaletteImpl
));
1235 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1236 return E_OUTOFMEMORY
;
1239 object
->lpVtbl
= &IWineD3DPalette_Vtbl
;
1241 object
->Flags
= Flags
;
1242 object
->parent
= Parent
;
1243 object
->device
= This
;
1244 object
->palNumEntries
= IWineD3DPaletteImpl_Size(Flags
);
1245 object
->hpal
= CreatePalette((const LOGPALETTE
*)&(object
->palVersion
));
1248 HeapFree( GetProcessHeap(), 0, object
);
1249 return E_OUTOFMEMORY
;
1252 hr
= IWineD3DPalette_SetEntries((IWineD3DPalette
*) object
, 0, 0, IWineD3DPaletteImpl_Size(Flags
), PalEnt
);
1254 IWineD3DPalette_Release((IWineD3DPalette
*) object
);
1258 *Palette
= (IWineD3DPalette
*) object
;
1263 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl
*This
, const char *filename
) {
1267 HDC dcb
= NULL
, dcs
= NULL
;
1268 WINEDDCOLORKEY colorkey
;
1270 hbm
= LoadImageA(NULL
, filename
, IMAGE_BITMAP
, 0, 0, LR_LOADFROMFILE
| LR_CREATEDIBSECTION
);
1273 GetObjectA(hbm
, sizeof(BITMAP
), &bm
);
1274 dcb
= CreateCompatibleDC(NULL
);
1276 SelectObject(dcb
, hbm
);
1280 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1281 * couldn't be loaded
1283 memset(&bm
, 0, sizeof(bm
));
1288 hr
= IWineD3DDevice_CreateSurface((IWineD3DDevice
*)This
, bm
.bmWidth
, bm
.bmHeight
, WINED3DFMT_B5G6R5_UNORM
, TRUE
,
1289 FALSE
, 0, &This
->logo_surface
, 0, WINED3DPOOL_DEFAULT
, WINED3DMULTISAMPLE_NONE
, 0, SURFACE_OPENGL
,
1290 NULL
, &wined3d_null_parent_ops
);
1292 ERR("Wine logo requested, but failed to create surface\n");
1297 hr
= IWineD3DSurface_GetDC(This
->logo_surface
, &dcs
);
1298 if(FAILED(hr
)) goto out
;
1299 BitBlt(dcs
, 0, 0, bm
.bmWidth
, bm
.bmHeight
, dcb
, 0, 0, SRCCOPY
);
1300 IWineD3DSurface_ReleaseDC(This
->logo_surface
, dcs
);
1302 colorkey
.dwColorSpaceLowValue
= 0;
1303 colorkey
.dwColorSpaceHighValue
= 0;
1304 IWineD3DSurface_SetColorKey(This
->logo_surface
, WINEDDCKEY_SRCBLT
, &colorkey
);
1306 /* Fill the surface with a white color to show that wined3d is there */
1307 IWineD3DDevice_ColorFill((IWineD3DDevice
*) This
, This
->logo_surface
, NULL
, 0xffffffff);
1311 if (dcb
) DeleteDC(dcb
);
1312 if (hbm
) DeleteObject(hbm
);
1315 /* Context activation is done by the caller. */
1316 static void create_dummy_textures(IWineD3DDeviceImpl
*This
)
1318 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
1320 /* Under DirectX you can have texture stage operations even if no texture is
1321 bound, whereas opengl will only do texture operations when a valid texture is
1322 bound. We emulate this by creating dummy textures and binding them to each
1323 texture stage, but disable all stages by default. Hence if a stage is enabled
1324 then the default texture will kick in until replaced by a SetTexture call */
1327 if (gl_info
->supported
[APPLE_CLIENT_STORAGE
])
1329 /* The dummy texture does not have client storage backing */
1330 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
1331 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1334 for (i
= 0; i
< gl_info
->limits
.textures
; ++i
)
1336 GLubyte white
= 255;
1338 /* Make appropriate texture active */
1339 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
+ i
));
1340 checkGLcall("glActiveTextureARB");
1342 /* Generate an opengl texture name */
1343 glGenTextures(1, &This
->dummyTextureName
[i
]);
1344 checkGLcall("glGenTextures");
1345 TRACE("Dummy Texture %d given name %d\n", i
, This
->dummyTextureName
[i
]);
1347 /* Generate a dummy 2d texture (not using 1d because they cause many
1348 * DRI drivers fall back to sw) */
1349 glBindTexture(GL_TEXTURE_2D
, This
->dummyTextureName
[i
]);
1350 checkGLcall("glBindTexture");
1352 glTexImage2D(GL_TEXTURE_2D
, 0, GL_LUMINANCE
, 1, 1, 0, GL_LUMINANCE
, GL_UNSIGNED_BYTE
, &white
);
1353 checkGLcall("glTexImage2D");
1356 if (gl_info
->supported
[APPLE_CLIENT_STORAGE
])
1358 /* Reenable because if supported it is enabled by default */
1359 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
1360 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1366 /* Context activation is done by the caller. */
1367 static void destroy_dummy_textures(IWineD3DDeviceImpl
*device
, const struct wined3d_gl_info
*gl_info
)
1370 glDeleteTextures(gl_info
->limits
.textures
, device
->dummyTextureName
);
1371 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1374 memset(device
->dummyTextureName
, 0, gl_info
->limits
.textures
* sizeof(*device
->dummyTextureName
));
1377 static HRESULT WINAPI
IWineD3DDeviceImpl_Init3D(IWineD3DDevice
*iface
,
1378 WINED3DPRESENT_PARAMETERS
*pPresentationParameters
)
1380 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1381 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
1382 IWineD3DSwapChainImpl
*swapchain
= NULL
;
1383 struct wined3d_context
*context
;
1388 TRACE("(%p)->(%p)\n", This
, pPresentationParameters
);
1390 if(This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
1391 if(!This
->adapter
->opengl
) return WINED3DERR_INVALIDCALL
;
1393 if (!pPresentationParameters
->Windowed
)
1395 This
->focus_window
= This
->createParms
.hFocusWindow
;
1396 if (!This
->focus_window
) This
->focus_window
= pPresentationParameters
->hDeviceWindow
;
1397 if (!wined3d_register_window(This
->focus_window
, This
))
1399 ERR("Failed to register window %p.\n", This
->focus_window
);
1404 TRACE("(%p) : Creating stateblock\n", This
);
1405 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1406 hr
= IWineD3DDevice_CreateStateBlock(iface
,
1408 (IWineD3DStateBlock
**)&This
->stateBlock
,
1410 if (WINED3D_OK
!= hr
) { /* Note: No parent needed for initial internal stateblock */
1411 WARN("Failed to create stateblock\n");
1414 TRACE("(%p) : Created stateblock (%p)\n", This
, This
->stateBlock
);
1415 This
->updateStateBlock
= This
->stateBlock
;
1416 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
1418 This
->render_targets
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
1419 sizeof(IWineD3DSurface
*) * gl_info
->limits
.buffers
);
1420 This
->draw_buffers
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
1421 sizeof(GLenum
) * gl_info
->limits
.buffers
);
1423 This
->NumberOfPalettes
= 1;
1424 This
->palettes
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(PALETTEENTRY
*));
1425 if(!This
->palettes
|| !This
->render_targets
|| !This
->draw_buffers
) {
1426 ERR("Out of memory!\n");
1430 This
->palettes
[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY
) * 256);
1431 if(!This
->palettes
[0]) {
1432 ERR("Out of memory!\n");
1436 for (i
= 0; i
< 256; ++i
) {
1437 This
->palettes
[0][i
].peRed
= 0xFF;
1438 This
->palettes
[0][i
].peGreen
= 0xFF;
1439 This
->palettes
[0][i
].peBlue
= 0xFF;
1440 This
->palettes
[0][i
].peFlags
= 0xFF;
1442 This
->currentPalette
= 0;
1444 /* Initialize the texture unit mapping to a 1:1 mapping */
1445 for (state
= 0; state
< MAX_COMBINED_SAMPLERS
; ++state
)
1447 if (state
< gl_info
->limits
.fragment_samplers
)
1449 This
->texUnitMap
[state
] = state
;
1450 This
->rev_tex_unit_map
[state
] = state
;
1452 This
->texUnitMap
[state
] = WINED3D_UNMAPPED_STAGE
;
1453 This
->rev_tex_unit_map
[state
] = WINED3D_UNMAPPED_STAGE
;
1457 if (This
->focus_window
) SetFocus(This
->focus_window
);
1459 /* Setup the implicit swapchain. This also initializes a context. */
1460 TRACE("Creating implicit swapchain\n");
1461 hr
= IWineD3DDeviceParent_CreateSwapChain(This
->device_parent
,
1462 pPresentationParameters
, (IWineD3DSwapChain
**)&swapchain
);
1465 WARN("Failed to create implicit swapchain\n");
1469 This
->NumberOfSwapChains
= 1;
1470 This
->swapchains
= HeapAlloc(GetProcessHeap(), 0, This
->NumberOfSwapChains
* sizeof(IWineD3DSwapChain
*));
1471 if(!This
->swapchains
) {
1472 ERR("Out of memory!\n");
1475 This
->swapchains
[0] = (IWineD3DSwapChain
*) swapchain
;
1477 if(swapchain
->backBuffer
&& swapchain
->backBuffer
[0]) {
1478 TRACE("Setting rendertarget to %p\n", swapchain
->backBuffer
);
1479 This
->render_targets
[0] = swapchain
->backBuffer
[0];
1482 TRACE("Setting rendertarget to %p\n", swapchain
->frontBuffer
);
1483 This
->render_targets
[0] = swapchain
->frontBuffer
;
1485 IWineD3DSurface_AddRef(This
->render_targets
[0]);
1487 /* Depth Stencil support */
1488 This
->stencilBufferTarget
= This
->auto_depth_stencil_buffer
;
1489 if (NULL
!= This
->stencilBufferTarget
) {
1490 IWineD3DSurface_AddRef(This
->stencilBufferTarget
);
1493 hr
= This
->shader_backend
->shader_alloc_private(iface
);
1495 TRACE("Shader private data couldn't be allocated\n");
1498 hr
= This
->frag_pipe
->alloc_private(iface
);
1500 TRACE("Fragment pipeline private data couldn't be allocated\n");
1503 hr
= This
->blitter
->alloc_private(iface
);
1505 TRACE("Blitter private data couldn't be allocated\n");
1509 /* Set up some starting GL setup */
1511 /* Setup all the devices defaults */
1512 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock
*)This
->stateBlock
);
1514 context
= context_acquire(This
, swapchain
->frontBuffer
, CTXUSAGE_RESOURCELOAD
);
1516 create_dummy_textures(This
);
1520 /* Initialize the current view state */
1521 This
->view_ident
= 1;
1522 This
->contexts
[0]->last_was_rhw
= 0;
1523 glGetIntegerv(GL_MAX_LIGHTS
, &This
->maxConcurrentLights
);
1524 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1526 switch(wined3d_settings
.offscreen_rendering_mode
) {
1528 This
->offscreenBuffer
= GL_COLOR_ATTACHMENT0
;
1532 This
->offscreenBuffer
= GL_BACK
;
1535 case ORM_BACKBUFFER
:
1537 if (context_get_current()->aux_buffers
> 0)
1539 TRACE("Using auxilliary buffer for offscreen rendering\n");
1540 This
->offscreenBuffer
= GL_AUX0
;
1542 TRACE("Using back buffer for offscreen rendering\n");
1543 This
->offscreenBuffer
= GL_BACK
;
1548 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This
, This
);
1551 context_release(context
);
1553 /* Clear the screen */
1554 IWineD3DDevice_Clear((IWineD3DDevice
*) This
, 0, NULL
,
1555 WINED3DCLEAR_TARGET
| pPresentationParameters
->EnableAutoDepthStencil
? WINED3DCLEAR_ZBUFFER
| WINED3DCLEAR_STENCIL
: 0,
1558 This
->d3d_initialized
= TRUE
;
1560 if(wined3d_settings
.logo
) {
1561 IWineD3DDeviceImpl_LoadLogo(This
, wined3d_settings
.logo
);
1563 This
->highest_dirty_ps_const
= 0;
1564 This
->highest_dirty_vs_const
= 0;
1568 HeapFree(GetProcessHeap(), 0, This
->render_targets
);
1569 HeapFree(GetProcessHeap(), 0, This
->draw_buffers
);
1570 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
1571 This
->NumberOfSwapChains
= 0;
1572 if(This
->palettes
) {
1573 HeapFree(GetProcessHeap(), 0, This
->palettes
[0]);
1574 HeapFree(GetProcessHeap(), 0, This
->palettes
);
1576 This
->NumberOfPalettes
= 0;
1578 IWineD3DSwapChain_Release( (IWineD3DSwapChain
*) swapchain
);
1580 if(This
->stateBlock
) {
1581 IWineD3DStateBlock_Release((IWineD3DStateBlock
*) This
->stateBlock
);
1582 This
->stateBlock
= NULL
;
1584 if (This
->blit_priv
) {
1585 This
->blitter
->free_private(iface
);
1587 if (This
->fragment_priv
) {
1588 This
->frag_pipe
->free_private(iface
);
1590 if (This
->shader_priv
) {
1591 This
->shader_backend
->shader_free_private(iface
);
1593 if (This
->focus_window
) wined3d_unregister_window(This
->focus_window
);
1597 static HRESULT WINAPI
IWineD3DDeviceImpl_InitGDI(IWineD3DDevice
*iface
,
1598 WINED3DPRESENT_PARAMETERS
*pPresentationParameters
)
1600 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1601 IWineD3DSwapChainImpl
*swapchain
= NULL
;
1604 /* Setup the implicit swapchain */
1605 TRACE("Creating implicit swapchain\n");
1606 hr
= IWineD3DDeviceParent_CreateSwapChain(This
->device_parent
,
1607 pPresentationParameters
, (IWineD3DSwapChain
**)&swapchain
);
1610 WARN("Failed to create implicit swapchain\n");
1614 This
->NumberOfSwapChains
= 1;
1615 This
->swapchains
= HeapAlloc(GetProcessHeap(), 0, This
->NumberOfSwapChains
* sizeof(IWineD3DSwapChain
*));
1616 if(!This
->swapchains
) {
1617 ERR("Out of memory!\n");
1620 This
->swapchains
[0] = (IWineD3DSwapChain
*) swapchain
;
1624 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
1628 static HRESULT WINAPI
device_unload_resource(IWineD3DResource
*resource
, void *ctx
)
1630 IWineD3DResource_UnLoad(resource
);
1631 IWineD3DResource_Release(resource
);
1635 static HRESULT WINAPI
IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice
*iface
,
1636 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain
)
1638 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1639 const struct wined3d_gl_info
*gl_info
;
1640 struct wined3d_context
*context
;
1643 TRACE("(%p)\n", This
);
1645 if(!This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
1647 /* I don't think that the interface guarantees that the device is destroyed from the same thread
1648 * it was created. Thus make sure a context is active for the glDelete* calls
1650 context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
1651 gl_info
= context
->gl_info
;
1653 if(This
->logo_surface
) IWineD3DSurface_Release(This
->logo_surface
);
1655 /* Unload resources */
1656 IWineD3DDevice_EnumResources(iface
, device_unload_resource
, NULL
);
1658 TRACE("Deleting high order patches\n");
1659 for(i
= 0; i
< PATCHMAP_SIZE
; i
++) {
1660 struct list
*e1
, *e2
;
1661 struct WineD3DRectPatch
*patch
;
1662 LIST_FOR_EACH_SAFE(e1
, e2
, &This
->patches
[i
]) {
1663 patch
= LIST_ENTRY(e1
, struct WineD3DRectPatch
, entry
);
1664 IWineD3DDevice_DeletePatch(iface
, patch
->Handle
);
1668 /* Delete the palette conversion shader if it is around */
1669 if(This
->paletteConversionShader
) {
1671 GL_EXTCALL(glDeleteProgramsARB(1, &This
->paletteConversionShader
));
1673 This
->paletteConversionShader
= 0;
1676 /* Delete the pbuffer context if there is any */
1677 if(This
->pbufferContext
) context_destroy(This
, This
->pbufferContext
);
1679 /* Delete the mouse cursor texture */
1680 if(This
->cursorTexture
) {
1682 glDeleteTextures(1, &This
->cursorTexture
);
1684 This
->cursorTexture
= 0;
1687 for (sampler
= 0; sampler
< MAX_FRAGMENT_SAMPLERS
; ++sampler
) {
1688 IWineD3DDevice_SetTexture(iface
, sampler
, NULL
);
1690 for (sampler
= 0; sampler
< MAX_VERTEX_SAMPLERS
; ++sampler
) {
1691 IWineD3DDevice_SetTexture(iface
, WINED3DVERTEXTEXTURESAMPLER0
+ sampler
, NULL
);
1694 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
1695 * private data, it might contain opengl pointers
1697 if(This
->depth_blt_texture
) {
1699 glDeleteTextures(1, &This
->depth_blt_texture
);
1701 This
->depth_blt_texture
= 0;
1703 if (This
->depth_blt_rb
) {
1705 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &This
->depth_blt_rb
);
1707 This
->depth_blt_rb
= 0;
1708 This
->depth_blt_rb_w
= 0;
1709 This
->depth_blt_rb_h
= 0;
1712 /* Release the update stateblock */
1713 if(IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
) > 0){
1714 if(This
->updateStateBlock
!= This
->stateBlock
)
1715 FIXME("(%p) Something's still holding the Update stateblock\n",This
);
1717 This
->updateStateBlock
= NULL
;
1719 { /* because were not doing proper internal refcounts releasing the primary state block
1720 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1721 to set this->stateBlock = NULL; first */
1722 IWineD3DStateBlock
*stateBlock
= (IWineD3DStateBlock
*)This
->stateBlock
;
1723 This
->stateBlock
= NULL
;
1725 /* Release the stateblock */
1726 if(IWineD3DStateBlock_Release(stateBlock
) > 0){
1727 FIXME("(%p) Something's still holding the Update stateblock\n",This
);
1731 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
1732 This
->blitter
->free_private(iface
);
1733 This
->frag_pipe
->free_private(iface
);
1734 This
->shader_backend
->shader_free_private(iface
);
1736 /* Release the buffers (with sanity checks)*/
1737 TRACE("Releasing the depth stencil buffer at %p\n", This
->stencilBufferTarget
);
1738 if(This
->stencilBufferTarget
!= NULL
&& (IWineD3DSurface_Release(This
->stencilBufferTarget
) >0)){
1739 if(This
->auto_depth_stencil_buffer
!= This
->stencilBufferTarget
)
1740 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This
);
1742 This
->stencilBufferTarget
= NULL
;
1744 TRACE("Releasing the render target at %p\n", This
->render_targets
[0]);
1745 if(IWineD3DSurface_Release(This
->render_targets
[0]) >0){
1746 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1748 TRACE("Setting rendertarget to NULL\n");
1749 This
->render_targets
[0] = NULL
;
1751 if (This
->auto_depth_stencil_buffer
) {
1752 if (IWineD3DSurface_Release(This
->auto_depth_stencil_buffer
) > 0)
1754 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This
);
1756 This
->auto_depth_stencil_buffer
= NULL
;
1759 context_release(context
);
1761 for(i
=0; i
< This
->NumberOfSwapChains
; i
++) {
1762 TRACE("Releasing the implicit swapchain %d\n", i
);
1763 if (D3DCB_DestroySwapChain(This
->swapchains
[i
]) > 0) {
1764 FIXME("(%p) Something's still holding the implicit swapchain\n", This
);
1768 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
1769 This
->swapchains
= NULL
;
1770 This
->NumberOfSwapChains
= 0;
1772 for (i
= 0; i
< This
->NumberOfPalettes
; i
++) HeapFree(GetProcessHeap(), 0, This
->palettes
[i
]);
1773 HeapFree(GetProcessHeap(), 0, This
->palettes
);
1774 This
->palettes
= NULL
;
1775 This
->NumberOfPalettes
= 0;
1777 HeapFree(GetProcessHeap(), 0, This
->render_targets
);
1778 HeapFree(GetProcessHeap(), 0, This
->draw_buffers
);
1779 This
->render_targets
= NULL
;
1780 This
->draw_buffers
= NULL
;
1782 This
->d3d_initialized
= FALSE
;
1784 if (This
->focus_window
) wined3d_unregister_window(This
->focus_window
);
1789 static HRESULT WINAPI
IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice
*iface
, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain
) {
1790 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1793 for(i
=0; i
< This
->NumberOfSwapChains
; i
++) {
1794 TRACE("Releasing the implicit swapchain %d\n", i
);
1795 if (D3DCB_DestroySwapChain(This
->swapchains
[i
]) > 0) {
1796 FIXME("(%p) Something's still holding the implicit swapchain\n", This
);
1800 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
1801 This
->swapchains
= NULL
;
1802 This
->NumberOfSwapChains
= 0;
1806 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
1807 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
1808 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
1810 * There is no way to deactivate thread safety once it is enabled.
1812 static void WINAPI
IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice
*iface
) {
1813 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1815 /*For now just store the flag(needed in case of ddraw) */
1816 This
->createParms
.BehaviorFlags
|= WINED3DCREATE_MULTITHREADED
;
1819 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
,
1820 const WINED3DDISPLAYMODE
* pMode
) {
1822 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1824 const struct GlPixelFormatDesc
*format_desc
= getFormatDescEntry(pMode
->Format
, &This
->adapter
->gl_info
);
1827 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This
, iSwapChain
, pMode
, pMode
->Width
, pMode
->Height
, pMode
->RefreshRate
, debug_d3dformat(pMode
->Format
));
1829 /* Resize the screen even without a window:
1830 * The app could have unset it with SetCooperativeLevel, but not called
1831 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1832 * but we don't have any hwnd
1835 memset(&devmode
, 0, sizeof(devmode
));
1836 devmode
.dmSize
= sizeof(devmode
);
1837 devmode
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
1838 devmode
.dmBitsPerPel
= format_desc
->byte_count
* 8;
1839 devmode
.dmPelsWidth
= pMode
->Width
;
1840 devmode
.dmPelsHeight
= pMode
->Height
;
1842 devmode
.dmDisplayFrequency
= pMode
->RefreshRate
;
1843 if (pMode
->RefreshRate
!= 0) {
1844 devmode
.dmFields
|= DM_DISPLAYFREQUENCY
;
1847 /* Only change the mode if necessary */
1848 if( (This
->ddraw_width
== pMode
->Width
) &&
1849 (This
->ddraw_height
== pMode
->Height
) &&
1850 (This
->ddraw_format
== pMode
->Format
) &&
1851 (pMode
->RefreshRate
== 0) ) {
1855 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
);
1856 if (ret
!= DISP_CHANGE_SUCCESSFUL
) {
1857 if(devmode
.dmDisplayFrequency
!= 0) {
1858 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1859 devmode
.dmFields
&= ~DM_DISPLAYFREQUENCY
;
1860 devmode
.dmDisplayFrequency
= 0;
1861 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
) != DISP_CHANGE_SUCCESSFUL
;
1863 if(ret
!= DISP_CHANGE_SUCCESSFUL
) {
1864 return WINED3DERR_NOTAVAILABLE
;
1868 /* Store the new values */
1869 This
->ddraw_width
= pMode
->Width
;
1870 This
->ddraw_height
= pMode
->Height
;
1871 This
->ddraw_format
= pMode
->Format
;
1873 /* And finally clip mouse to our screen */
1874 SetRect(&clip_rc
, 0, 0, pMode
->Width
, pMode
->Height
);
1875 ClipCursor(&clip_rc
);
1880 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice
*iface
, IWineD3D
**ppD3D
) {
1881 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1882 *ppD3D
= This
->wined3d
;
1883 TRACE("Returning %p.\n", *ppD3D
);
1884 IWineD3D_AddRef(*ppD3D
);
1888 static UINT WINAPI
IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice
*iface
) {
1889 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1891 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This
,
1892 (This
->adapter
->TextureRam
/(1024*1024)),
1893 ((This
->adapter
->TextureRam
- This
->adapter
->UsedTextureRam
) / (1024*1024)));
1894 /* return simulated texture memory left */
1895 return (This
->adapter
->TextureRam
- This
->adapter
->UsedTextureRam
);
1899 * Get / Set Stream Source
1901 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice
*iface
, UINT StreamNumber
,
1902 IWineD3DBuffer
*pStreamData
, UINT OffsetInBytes
, UINT Stride
)
1904 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1905 IWineD3DBuffer
*oldSrc
;
1907 if (StreamNumber
>= MAX_STREAMS
) {
1908 WARN("Stream out of range %d\n", StreamNumber
);
1909 return WINED3DERR_INVALIDCALL
;
1910 } else if(OffsetInBytes
& 0x3) {
1911 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes
);
1912 return WINED3DERR_INVALIDCALL
;
1915 oldSrc
= This
->updateStateBlock
->streamSource
[StreamNumber
];
1916 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This
, StreamNumber
, oldSrc
, pStreamData
, OffsetInBytes
, Stride
);
1918 This
->updateStateBlock
->changed
.streamSource
|= 1 << StreamNumber
;
1920 if(oldSrc
== pStreamData
&&
1921 This
->updateStateBlock
->streamStride
[StreamNumber
] == Stride
&&
1922 This
->updateStateBlock
->streamOffset
[StreamNumber
] == OffsetInBytes
) {
1923 TRACE("Application is setting the old values over, nothing to do\n");
1927 This
->updateStateBlock
->streamSource
[StreamNumber
] = pStreamData
;
1929 This
->updateStateBlock
->streamStride
[StreamNumber
] = Stride
;
1930 This
->updateStateBlock
->streamOffset
[StreamNumber
] = OffsetInBytes
;
1933 /* Handle recording of state blocks */
1934 if (This
->isRecordingState
) {
1935 TRACE("Recording... not performing anything\n");
1936 if (pStreamData
) IWineD3DBuffer_AddRef(pStreamData
);
1937 if (oldSrc
) IWineD3DBuffer_Release(oldSrc
);
1941 if (pStreamData
!= NULL
) {
1942 InterlockedIncrement(&((struct wined3d_buffer
*)pStreamData
)->bind_count
);
1943 IWineD3DBuffer_AddRef(pStreamData
);
1945 if (oldSrc
!= NULL
) {
1946 InterlockedDecrement(&((struct wined3d_buffer
*)oldSrc
)->bind_count
);
1947 IWineD3DBuffer_Release(oldSrc
);
1950 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
1955 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice
*iface
,
1956 UINT StreamNumber
, IWineD3DBuffer
**pStream
, UINT
*pOffset
, UINT
*pStride
)
1958 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1960 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This
, StreamNumber
,
1961 This
->stateBlock
->streamSource
[StreamNumber
],
1962 This
->stateBlock
->streamOffset
[StreamNumber
],
1963 This
->stateBlock
->streamStride
[StreamNumber
]);
1965 if (StreamNumber
>= MAX_STREAMS
) {
1966 WARN("Stream out of range %d\n", StreamNumber
);
1967 return WINED3DERR_INVALIDCALL
;
1969 *pStream
= This
->stateBlock
->streamSource
[StreamNumber
];
1970 *pStride
= This
->stateBlock
->streamStride
[StreamNumber
];
1972 *pOffset
= This
->stateBlock
->streamOffset
[StreamNumber
];
1975 if (*pStream
!= NULL
) {
1976 IWineD3DBuffer_AddRef(*pStream
); /* We have created a new reference to the VB */
1981 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT Divider
) {
1982 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1983 UINT oldFlags
= This
->updateStateBlock
->streamFlags
[StreamNumber
];
1984 UINT oldFreq
= This
->updateStateBlock
->streamFreq
[StreamNumber
];
1986 /* Verify input at least in d3d9 this is invalid*/
1987 if( (Divider
& WINED3DSTREAMSOURCE_INSTANCEDATA
) && (Divider
& WINED3DSTREAMSOURCE_INDEXEDDATA
)){
1988 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
1989 return WINED3DERR_INVALIDCALL
;
1991 if( (Divider
& WINED3DSTREAMSOURCE_INSTANCEDATA
) && StreamNumber
== 0 ){
1992 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
1993 return WINED3DERR_INVALIDCALL
;
1996 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
1997 return WINED3DERR_INVALIDCALL
;
2000 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This
, StreamNumber
, Divider
);
2001 This
->updateStateBlock
->streamFlags
[StreamNumber
] = Divider
& (WINED3DSTREAMSOURCE_INSTANCEDATA
| WINED3DSTREAMSOURCE_INDEXEDDATA
);
2003 This
->updateStateBlock
->changed
.streamFreq
|= 1 << StreamNumber
;
2004 This
->updateStateBlock
->streamFreq
[StreamNumber
] = Divider
& 0x7FFFFF;
2006 if(This
->updateStateBlock
->streamFreq
[StreamNumber
] != oldFreq
||
2007 This
->updateStateBlock
->streamFlags
[StreamNumber
] != oldFlags
) {
2008 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2014 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT
* Divider
) {
2015 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2017 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This
, StreamNumber
, Divider
);
2018 *Divider
= This
->updateStateBlock
->streamFreq
[StreamNumber
] | This
->updateStateBlock
->streamFlags
[StreamNumber
];
2020 TRACE("(%p) : returning %d\n", This
, *Divider
);
2026 * Get / Set & Multiply Transform
2028 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE d3dts
, CONST WINED3DMATRIX
* lpmatrix
) {
2029 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2031 /* Most of this routine, comments included copied from ddraw tree initially: */
2032 TRACE("(%p) : Transform State=%s\n", This
, debug_d3dtstype(d3dts
));
2034 /* Handle recording of state blocks */
2035 if (This
->isRecordingState
) {
2036 TRACE("Recording... not performing anything\n");
2037 This
->updateStateBlock
->changed
.transform
[d3dts
>> 5] |= 1 << (d3dts
& 0x1f);
2038 This
->updateStateBlock
->transforms
[d3dts
] = *lpmatrix
;
2043 * If the new matrix is the same as the current one,
2044 * we cut off any further processing. this seems to be a reasonable
2045 * optimization because as was noticed, some apps (warcraft3 for example)
2046 * tend towards setting the same matrix repeatedly for some reason.
2048 * From here on we assume that the new matrix is different, wherever it matters.
2050 if (!memcmp(&This
->stateBlock
->transforms
[d3dts
].u
.m
[0][0], lpmatrix
, sizeof(WINED3DMATRIX
))) {
2051 TRACE("The app is setting the same matrix over again\n");
2054 conv_mat(lpmatrix
, &This
->stateBlock
->transforms
[d3dts
].u
.m
[0][0]);
2058 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2059 where ViewMat = Camera space, WorldMat = world space.
2061 In OpenGL, camera and world space is combined into GL_MODELVIEW
2062 matrix. The Projection matrix stay projection matrix.
2065 /* Capture the times we can just ignore the change for now */
2066 if (d3dts
== WINED3DTS_VIEW
) { /* handle the VIEW matrix */
2067 This
->view_ident
= !memcmp(lpmatrix
, identity
, 16 * sizeof(float));
2068 /* Handled by the state manager */
2071 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TRANSFORM(d3dts
));
2075 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, WINED3DMATRIX
* pMatrix
) {
2076 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2077 TRACE("(%p) : for Transform State %s\n", This
, debug_d3dtstype(State
));
2078 *pMatrix
= This
->stateBlock
->transforms
[State
];
2082 static HRESULT WINAPI
IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, CONST WINED3DMATRIX
* pMatrix
) {
2083 const WINED3DMATRIX
*mat
= NULL
;
2086 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2087 * below means it will be recorded in a state block change, but it
2088 * works regardless where it is recorded.
2089 * If this is found to be wrong, change to StateBlock.
2091 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2092 TRACE("(%p) : For state %s\n", This
, debug_d3dtstype(State
));
2094 if (State
<= HIGHEST_TRANSFORMSTATE
)
2096 mat
= &This
->updateStateBlock
->transforms
[State
];
2098 FIXME("Unhandled transform state!!\n");
2101 multiply_matrix(&temp
, mat
, pMatrix
);
2103 /* Apply change via set transform - will reapply to eg. lights this way */
2104 return IWineD3DDeviceImpl_SetTransform(iface
, State
, &temp
);
2110 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2111 you can reference any indexes you want as long as that number max are enabled at any
2112 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2113 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2114 but when recording, just build a chain pretty much of commands to be replayed. */
2116 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLight(IWineD3DDevice
*iface
, DWORD Index
, CONST WINED3DLIGHT
* pLight
) {
2118 struct wined3d_light_info
*object
= NULL
;
2119 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2122 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2123 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This
, Index
, pLight
, Hi
);
2125 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2129 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2130 return WINED3DERR_INVALIDCALL
;
2133 switch(pLight
->Type
) {
2134 case WINED3DLIGHT_POINT
:
2135 case WINED3DLIGHT_SPOT
:
2136 case WINED3DLIGHT_PARALLELPOINT
:
2137 case WINED3DLIGHT_GLSPOT
:
2138 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2141 if (pLight
->Attenuation0
< 0.0f
|| pLight
->Attenuation1
< 0.0f
|| pLight
->Attenuation2
< 0.0f
)
2143 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2144 return WINED3DERR_INVALIDCALL
;
2148 case WINED3DLIGHT_DIRECTIONAL
:
2149 /* Ignores attenuation */
2153 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2154 return WINED3DERR_INVALIDCALL
;
2157 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
])
2159 object
= LIST_ENTRY(e
, struct wined3d_light_info
, entry
);
2160 if(object
->OriginalIndex
== Index
) break;
2165 TRACE("Adding new light\n");
2166 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
2168 ERR("Out of memory error when allocating a light\n");
2169 return E_OUTOFMEMORY
;
2171 list_add_head(&This
->updateStateBlock
->lightMap
[Hi
], &object
->entry
);
2172 object
->glIndex
= -1;
2173 object
->OriginalIndex
= Index
;
2176 /* Initialize the object */
2177 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
,
2178 pLight
->Diffuse
.r
, pLight
->Diffuse
.g
, pLight
->Diffuse
.b
, pLight
->Diffuse
.a
,
2179 pLight
->Specular
.r
, pLight
->Specular
.g
, pLight
->Specular
.b
, pLight
->Specular
.a
,
2180 pLight
->Ambient
.r
, pLight
->Ambient
.g
, pLight
->Ambient
.b
, pLight
->Ambient
.a
);
2181 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight
->Position
.x
, pLight
->Position
.y
, pLight
->Position
.z
,
2182 pLight
->Direction
.x
, pLight
->Direction
.y
, pLight
->Direction
.z
);
2183 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight
->Range
, pLight
->Falloff
, pLight
->Theta
, pLight
->Phi
);
2185 /* Save away the information */
2186 object
->OriginalParms
= *pLight
;
2188 switch (pLight
->Type
) {
2189 case WINED3DLIGHT_POINT
:
2191 object
->lightPosn
[0] = pLight
->Position
.x
;
2192 object
->lightPosn
[1] = pLight
->Position
.y
;
2193 object
->lightPosn
[2] = pLight
->Position
.z
;
2194 object
->lightPosn
[3] = 1.0f
;
2195 object
->cutoff
= 180.0f
;
2199 case WINED3DLIGHT_DIRECTIONAL
:
2201 object
->lightPosn
[0] = -pLight
->Direction
.x
;
2202 object
->lightPosn
[1] = -pLight
->Direction
.y
;
2203 object
->lightPosn
[2] = -pLight
->Direction
.z
;
2204 object
->lightPosn
[3] = 0.0f
;
2205 object
->exponent
= 0.0f
;
2206 object
->cutoff
= 180.0f
;
2209 case WINED3DLIGHT_SPOT
:
2211 object
->lightPosn
[0] = pLight
->Position
.x
;
2212 object
->lightPosn
[1] = pLight
->Position
.y
;
2213 object
->lightPosn
[2] = pLight
->Position
.z
;
2214 object
->lightPosn
[3] = 1.0f
;
2217 object
->lightDirn
[0] = pLight
->Direction
.x
;
2218 object
->lightDirn
[1] = pLight
->Direction
.y
;
2219 object
->lightDirn
[2] = pLight
->Direction
.z
;
2220 object
->lightDirn
[3] = 1.0f
;
2223 * opengl-ish and d3d-ish spot lights use too different models for the
2224 * light "intensity" as a function of the angle towards the main light direction,
2225 * so we only can approximate very roughly.
2226 * however spot lights are rather rarely used in games (if ever used at all).
2227 * furthermore if still used, probably nobody pays attention to such details.
2229 if (pLight
->Falloff
== 0) {
2230 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2231 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2232 * will always be 1.0 for both of them, and we don't have to care for the
2233 * rest of the rather complex calculation
2235 object
->exponent
= 0.0f
;
2237 rho
= pLight
->Theta
+ (pLight
->Phi
- pLight
->Theta
)/(2*pLight
->Falloff
);
2238 if (rho
< 0.0001f
) rho
= 0.0001f
;
2239 object
->exponent
= -0.3f
/logf(cosf(rho
/2));
2241 if (object
->exponent
> 128.0f
)
2243 object
->exponent
= 128.0f
;
2245 object
->cutoff
= pLight
->Phi
*90/M_PI
;
2251 FIXME("Unrecognized light type %d\n", pLight
->Type
);
2254 /* Update the live definitions if the light is currently assigned a glIndex */
2255 if (object
->glIndex
!= -1 && !This
->isRecordingState
) {
2256 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(object
->glIndex
));
2261 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLight(IWineD3DDevice
*iface
, DWORD Index
, WINED3DLIGHT
*pLight
)
2263 struct wined3d_light_info
*lightInfo
= NULL
;
2264 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2265 DWORD Hi
= LIGHTMAP_HASHFUNC(Index
);
2267 TRACE("(%p) : Idx(%d), pLight(%p)\n", This
, Index
, pLight
);
2269 LIST_FOR_EACH(e
, &This
->stateBlock
->lightMap
[Hi
])
2271 lightInfo
= LIST_ENTRY(e
, struct wined3d_light_info
, entry
);
2272 if(lightInfo
->OriginalIndex
== Index
) break;
2276 if (lightInfo
== NULL
) {
2277 TRACE("Light information requested but light not defined\n");
2278 return WINED3DERR_INVALIDCALL
;
2281 *pLight
= lightInfo
->OriginalParms
;
2286 * Get / Set Light Enable
2287 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2289 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice
*iface
, DWORD Index
, BOOL Enable
)
2291 struct wined3d_light_info
*lightInfo
= NULL
;
2292 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2293 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2295 TRACE("(%p) : Idx(%d), enable? %d\n", This
, Index
, Enable
);
2297 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
])
2299 lightInfo
= LIST_ENTRY(e
, struct wined3d_light_info
, entry
);
2300 if(lightInfo
->OriginalIndex
== Index
) break;
2303 TRACE("Found light: %p\n", lightInfo
);
2305 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2306 if (lightInfo
== NULL
) {
2308 TRACE("Light enabled requested but light not defined, so defining one!\n");
2309 IWineD3DDeviceImpl_SetLight(iface
, Index
, &WINED3D_default_light
);
2311 /* Search for it again! Should be fairly quick as near head of list */
2312 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
])
2314 lightInfo
= LIST_ENTRY(e
, struct wined3d_light_info
, entry
);
2315 if(lightInfo
->OriginalIndex
== Index
) break;
2318 if (lightInfo
== NULL
) {
2319 FIXME("Adding default lights has failed dismally\n");
2320 return WINED3DERR_INVALIDCALL
;
2325 if(lightInfo
->glIndex
!= -1) {
2326 if(!This
->isRecordingState
) {
2327 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(lightInfo
->glIndex
));
2330 This
->updateStateBlock
->activeLights
[lightInfo
->glIndex
] = NULL
;
2331 lightInfo
->glIndex
= -1;
2333 TRACE("Light already disabled, nothing to do\n");
2335 lightInfo
->enabled
= FALSE
;
2337 lightInfo
->enabled
= TRUE
;
2338 if (lightInfo
->glIndex
!= -1) {
2340 TRACE("Nothing to do as light was enabled\n");
2343 /* Find a free gl light */
2344 for(i
= 0; i
< This
->maxConcurrentLights
; i
++) {
2345 if(This
->updateStateBlock
->activeLights
[i
] == NULL
) {
2346 This
->updateStateBlock
->activeLights
[i
] = lightInfo
;
2347 lightInfo
->glIndex
= i
;
2351 if(lightInfo
->glIndex
== -1) {
2352 /* Our tests show that Windows returns D3D_OK in this situation, even with
2353 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2354 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2355 * as well for those lights.
2357 * TODO: Test how this affects rendering
2359 WARN("Too many concurrently active lights\n");
2363 /* i == lightInfo->glIndex */
2364 if(!This
->isRecordingState
) {
2365 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(i
));
2373 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice
*iface
, DWORD Index
,BOOL
* pEnable
)
2375 struct wined3d_light_info
*lightInfo
= NULL
;
2376 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2378 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2379 TRACE("(%p) : for idx(%d)\n", This
, Index
);
2381 LIST_FOR_EACH(e
, &This
->stateBlock
->lightMap
[Hi
])
2383 lightInfo
= LIST_ENTRY(e
, struct wined3d_light_info
, entry
);
2384 if(lightInfo
->OriginalIndex
== Index
) break;
2388 if (lightInfo
== NULL
) {
2389 TRACE("Light enabled state requested but light not defined\n");
2390 return WINED3DERR_INVALIDCALL
;
2392 /* true is 128 according to SetLightEnable */
2393 *pEnable
= lightInfo
->enabled
? 128 : 0;
2398 * Get / Set Clip Planes
2400 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, CONST
float *pPlane
) {
2401 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2402 TRACE("(%p) : for idx %d, %p\n", This
, Index
, pPlane
);
2404 /* Validate Index */
2405 if (Index
>= This
->adapter
->gl_info
.limits
.clipplanes
)
2407 TRACE("Application has requested clipplane this device doesn't support\n");
2408 return WINED3DERR_INVALIDCALL
;
2411 This
->updateStateBlock
->changed
.clipplane
|= 1 << Index
;
2413 if(This
->updateStateBlock
->clipplane
[Index
][0] == pPlane
[0] &&
2414 This
->updateStateBlock
->clipplane
[Index
][1] == pPlane
[1] &&
2415 This
->updateStateBlock
->clipplane
[Index
][2] == pPlane
[2] &&
2416 This
->updateStateBlock
->clipplane
[Index
][3] == pPlane
[3]) {
2417 TRACE("Application is setting old values over, nothing to do\n");
2421 This
->updateStateBlock
->clipplane
[Index
][0] = pPlane
[0];
2422 This
->updateStateBlock
->clipplane
[Index
][1] = pPlane
[1];
2423 This
->updateStateBlock
->clipplane
[Index
][2] = pPlane
[2];
2424 This
->updateStateBlock
->clipplane
[Index
][3] = pPlane
[3];
2426 /* Handle recording of state blocks */
2427 if (This
->isRecordingState
) {
2428 TRACE("Recording... not performing anything\n");
2432 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_CLIPPLANE(Index
));
2437 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, float *pPlane
) {
2438 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2439 TRACE("(%p) : for idx %d\n", This
, Index
);
2441 /* Validate Index */
2442 if (Index
>= This
->adapter
->gl_info
.limits
.clipplanes
)
2444 TRACE("Application has requested clipplane this device doesn't support\n");
2445 return WINED3DERR_INVALIDCALL
;
2448 pPlane
[0] = This
->stateBlock
->clipplane
[Index
][0];
2449 pPlane
[1] = This
->stateBlock
->clipplane
[Index
][1];
2450 pPlane
[2] = This
->stateBlock
->clipplane
[Index
][2];
2451 pPlane
[3] = This
->stateBlock
->clipplane
[Index
][3];
2456 * Get / Set Clip Plane Status
2457 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2459 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice
*iface
, CONST WINED3DCLIPSTATUS
* pClipStatus
) {
2460 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2461 FIXME("(%p) : stub\n", This
);
2462 if (NULL
== pClipStatus
) {
2463 return WINED3DERR_INVALIDCALL
;
2465 This
->updateStateBlock
->clip_status
.ClipUnion
= pClipStatus
->ClipUnion
;
2466 This
->updateStateBlock
->clip_status
.ClipIntersection
= pClipStatus
->ClipIntersection
;
2470 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice
*iface
, WINED3DCLIPSTATUS
* pClipStatus
) {
2471 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2472 FIXME("(%p) : stub\n", This
);
2473 if (NULL
== pClipStatus
) {
2474 return WINED3DERR_INVALIDCALL
;
2476 pClipStatus
->ClipUnion
= This
->updateStateBlock
->clip_status
.ClipUnion
;
2477 pClipStatus
->ClipIntersection
= This
->updateStateBlock
->clip_status
.ClipIntersection
;
2482 * Get / Set Material
2484 static HRESULT WINAPI
IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice
*iface
, CONST WINED3DMATERIAL
* pMaterial
) {
2485 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2487 This
->updateStateBlock
->changed
.material
= TRUE
;
2488 This
->updateStateBlock
->material
= *pMaterial
;
2490 /* Handle recording of state blocks */
2491 if (This
->isRecordingState
) {
2492 TRACE("Recording... not performing anything\n");
2496 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_MATERIAL
);
2500 static HRESULT WINAPI
IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice
*iface
, WINED3DMATERIAL
* pMaterial
) {
2501 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2502 *pMaterial
= This
->updateStateBlock
->material
;
2503 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This
, pMaterial
->Diffuse
.r
, pMaterial
->Diffuse
.g
,
2504 pMaterial
->Diffuse
.b
, pMaterial
->Diffuse
.a
);
2505 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This
, pMaterial
->Ambient
.r
, pMaterial
->Ambient
.g
,
2506 pMaterial
->Ambient
.b
, pMaterial
->Ambient
.a
);
2507 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This
, pMaterial
->Specular
.r
, pMaterial
->Specular
.g
,
2508 pMaterial
->Specular
.b
, pMaterial
->Specular
.a
);
2509 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This
, pMaterial
->Emissive
.r
, pMaterial
->Emissive
.g
,
2510 pMaterial
->Emissive
.b
, pMaterial
->Emissive
.a
);
2511 TRACE("(%p) : Power (%f)\n", This
, pMaterial
->Power
);
2519 static HRESULT WINAPI
IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice
*iface
,
2520 IWineD3DBuffer
*pIndexData
, WINED3DFORMAT fmt
)
2522 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2523 IWineD3DBuffer
*oldIdxs
;
2525 TRACE("(%p) : Setting to %p\n", This
, pIndexData
);
2526 oldIdxs
= This
->updateStateBlock
->pIndexData
;
2528 This
->updateStateBlock
->changed
.indices
= TRUE
;
2529 This
->updateStateBlock
->pIndexData
= pIndexData
;
2530 This
->updateStateBlock
->IndexFmt
= fmt
;
2532 /* Handle recording of state blocks */
2533 if (This
->isRecordingState
) {
2534 TRACE("Recording... not performing anything\n");
2535 if(pIndexData
) IWineD3DBuffer_AddRef(pIndexData
);
2536 if(oldIdxs
) IWineD3DBuffer_Release(oldIdxs
);
2540 if(oldIdxs
!= pIndexData
) {
2541 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
2543 InterlockedIncrement(&((struct wined3d_buffer
*)pIndexData
)->bind_count
);
2544 IWineD3DBuffer_AddRef(pIndexData
);
2547 InterlockedDecrement(&((struct wined3d_buffer
*)oldIdxs
)->bind_count
);
2548 IWineD3DBuffer_Release(oldIdxs
);
2555 static HRESULT WINAPI
IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice
*iface
, IWineD3DBuffer
**ppIndexData
)
2557 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2559 *ppIndexData
= This
->stateBlock
->pIndexData
;
2561 /* up ref count on ppindexdata */
2563 IWineD3DBuffer_AddRef(*ppIndexData
);
2564 TRACE("(%p) index data set to %p\n", This
, ppIndexData
);
2566 TRACE("(%p) No index data set\n", This
);
2568 TRACE("Returning %p\n", *ppIndexData
);
2573 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2574 static HRESULT WINAPI
IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice
*iface
, INT BaseIndex
) {
2575 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2576 TRACE("(%p)->(%d)\n", This
, BaseIndex
);
2578 if(This
->updateStateBlock
->baseVertexIndex
== BaseIndex
) {
2579 TRACE("Application is setting the old value over, nothing to do\n");
2583 This
->updateStateBlock
->baseVertexIndex
= BaseIndex
;
2585 if (This
->isRecordingState
) {
2586 TRACE("Recording... not performing anything\n");
2589 /* The base vertex index affects the stream sources */
2590 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2594 static HRESULT WINAPI
IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice
*iface
, INT
* base_index
) {
2595 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2596 TRACE("(%p) : base_index %p\n", This
, base_index
);
2598 *base_index
= This
->stateBlock
->baseVertexIndex
;
2600 TRACE("Returning %u\n", *base_index
);
2606 * Get / Set Viewports
2608 static HRESULT WINAPI
IWineD3DDeviceImpl_SetViewport(IWineD3DDevice
*iface
, CONST WINED3DVIEWPORT
* pViewport
) {
2609 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2611 TRACE("(%p)\n", This
);
2612 This
->updateStateBlock
->changed
.viewport
= TRUE
;
2613 This
->updateStateBlock
->viewport
= *pViewport
;
2615 /* Handle recording of state blocks */
2616 if (This
->isRecordingState
) {
2617 TRACE("Recording... not performing anything\n");
2621 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This
,
2622 pViewport
->X
, pViewport
->Y
, pViewport
->Width
, pViewport
->Height
, pViewport
->MinZ
, pViewport
->MaxZ
);
2624 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VIEWPORT
);
2629 static HRESULT WINAPI
IWineD3DDeviceImpl_GetViewport(IWineD3DDevice
*iface
, WINED3DVIEWPORT
* pViewport
) {
2630 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2631 TRACE("(%p)\n", This
);
2632 *pViewport
= This
->stateBlock
->viewport
;
2637 * Get / Set Render States
2638 * TODO: Verify against dx9 definitions
2640 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice
*iface
, WINED3DRENDERSTATETYPE State
, DWORD Value
) {
2642 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2643 DWORD oldValue
= This
->stateBlock
->renderState
[State
];
2645 TRACE("(%p)->state = %s(%d), value = %d\n", This
, debug_d3drenderstate(State
), State
, Value
);
2647 This
->updateStateBlock
->changed
.renderState
[State
>> 5] |= 1 << (State
& 0x1f);
2648 This
->updateStateBlock
->renderState
[State
] = Value
;
2650 /* Handle recording of state blocks */
2651 if (This
->isRecordingState
) {
2652 TRACE("Recording... not performing anything\n");
2656 /* Compared here and not before the assignment to allow proper stateblock recording */
2657 if(Value
== oldValue
) {
2658 TRACE("Application is setting the old value over, nothing to do\n");
2660 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(State
));
2666 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice
*iface
, WINED3DRENDERSTATETYPE State
, DWORD
*pValue
) {
2667 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2668 TRACE("(%p) for State %d = %d\n", This
, State
, This
->stateBlock
->renderState
[State
]);
2669 *pValue
= This
->stateBlock
->renderState
[State
];
2674 * Get / Set Sampler States
2675 * TODO: Verify against dx9 definitions
2678 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD Value
) {
2679 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2682 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2683 This
, Sampler
, debug_d3dsamplerstate(Type
), Type
, Value
);
2685 if (Sampler
>= WINED3DVERTEXTEXTURESAMPLER0
&& Sampler
<= WINED3DVERTEXTEXTURESAMPLER3
) {
2686 Sampler
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
2689 if (Sampler
>= sizeof(This
->stateBlock
->samplerState
)/sizeof(This
->stateBlock
->samplerState
[0])) {
2690 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler
);
2691 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
2694 * SetSampler is designed to allow for more than the standard up to 8 textures
2695 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2696 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2698 * http://developer.nvidia.com/object/General_FAQ.html#t6
2700 * There are two new settings for GForce
2702 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2703 * and the texture one:
2704 * GL_MAX_TEXTURE_COORDS_ARB.
2705 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2708 oldValue
= This
->stateBlock
->samplerState
[Sampler
][Type
];
2709 This
->updateStateBlock
->samplerState
[Sampler
][Type
] = Value
;
2710 This
->updateStateBlock
->changed
.samplerState
[Sampler
] |= 1 << Type
;
2712 /* Handle recording of state blocks */
2713 if (This
->isRecordingState
) {
2714 TRACE("Recording... not performing anything\n");
2718 if(oldValue
== Value
) {
2719 TRACE("Application is setting the old value over, nothing to do\n");
2723 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(Sampler
));
2728 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD
* Value
) {
2729 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2731 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2732 This
, Sampler
, debug_d3dsamplerstate(Type
), Type
);
2734 if (Sampler
>= WINED3DVERTEXTEXTURESAMPLER0
&& Sampler
<= WINED3DVERTEXTEXTURESAMPLER3
) {
2735 Sampler
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
2738 if (Sampler
>= sizeof(This
->stateBlock
->samplerState
)/sizeof(This
->stateBlock
->samplerState
[0])) {
2739 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler
);
2740 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
2742 *Value
= This
->stateBlock
->samplerState
[Sampler
][Type
];
2743 TRACE("(%p) : Returning %#x\n", This
, *Value
);
2748 static HRESULT WINAPI
IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice
*iface
, CONST RECT
* pRect
) {
2749 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2751 This
->updateStateBlock
->changed
.scissorRect
= TRUE
;
2752 if(EqualRect(&This
->updateStateBlock
->scissorRect
, pRect
)) {
2753 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2756 CopyRect(&This
->updateStateBlock
->scissorRect
, pRect
);
2758 if(This
->isRecordingState
) {
2759 TRACE("Recording... not performing anything\n");
2763 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SCISSORRECT
);
2768 static HRESULT WINAPI
IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice
*iface
, RECT
* pRect
) {
2769 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2771 *pRect
= This
->updateStateBlock
->scissorRect
;
2772 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This
, pRect
->left
, pRect
->top
, pRect
->right
, pRect
->bottom
);
2776 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
* pDecl
) {
2777 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2778 IWineD3DVertexDeclaration
*oldDecl
= This
->updateStateBlock
->vertexDecl
;
2780 TRACE("(%p) : pDecl=%p\n", This
, pDecl
);
2782 if (pDecl
) IWineD3DVertexDeclaration_AddRef(pDecl
);
2783 if (oldDecl
) IWineD3DVertexDeclaration_Release(oldDecl
);
2785 This
->updateStateBlock
->vertexDecl
= pDecl
;
2786 This
->updateStateBlock
->changed
.vertexDecl
= TRUE
;
2788 if (This
->isRecordingState
) {
2789 TRACE("Recording... not performing anything\n");
2791 } else if(pDecl
== oldDecl
) {
2792 /* Checked after the assignment to allow proper stateblock recording */
2793 TRACE("Application is setting the old declaration over, nothing to do\n");
2797 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
2801 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppDecl
) {
2802 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2804 TRACE("(%p) : ppDecl=%p\n", This
, ppDecl
);
2806 *ppDecl
= This
->stateBlock
->vertexDecl
;
2807 if (NULL
!= *ppDecl
) IWineD3DVertexDeclaration_AddRef(*ppDecl
);
2811 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
* pShader
) {
2812 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2813 IWineD3DVertexShader
* oldShader
= This
->updateStateBlock
->vertexShader
;
2815 This
->updateStateBlock
->vertexShader
= pShader
;
2816 This
->updateStateBlock
->changed
.vertexShader
= TRUE
;
2818 if (This
->isRecordingState
) {
2819 if(pShader
) IWineD3DVertexShader_AddRef(pShader
);
2820 if(oldShader
) IWineD3DVertexShader_Release(oldShader
);
2821 TRACE("Recording... not performing anything\n");
2823 } else if(oldShader
== pShader
) {
2824 /* Checked here to allow proper stateblock recording */
2825 TRACE("App is setting the old shader over, nothing to do\n");
2829 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
2830 if(pShader
) IWineD3DVertexShader_AddRef(pShader
);
2831 if(oldShader
) IWineD3DVertexShader_Release(oldShader
);
2833 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VSHADER
);
2838 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
** ppShader
) {
2839 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2841 if (NULL
== ppShader
) {
2842 return WINED3DERR_INVALIDCALL
;
2844 *ppShader
= This
->stateBlock
->vertexShader
;
2845 if( NULL
!= *ppShader
)
2846 IWineD3DVertexShader_AddRef(*ppShader
);
2848 TRACE("(%p) : returning %p\n", This
, *ppShader
);
2852 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantB(
2853 IWineD3DDevice
*iface
,
2855 CONST BOOL
*srcData
,
2858 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2859 unsigned int i
, cnt
= min(count
, MAX_CONST_B
- start
);
2861 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2862 iface
, srcData
, start
, count
);
2864 if (!srcData
|| start
>= MAX_CONST_B
) return WINED3DERR_INVALIDCALL
;
2866 memcpy(&This
->updateStateBlock
->vertexShaderConstantB
[start
], srcData
, cnt
* sizeof(BOOL
));
2867 for (i
= 0; i
< cnt
; i
++)
2868 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
2870 for (i
= start
; i
< cnt
+ start
; ++i
) {
2871 This
->updateStateBlock
->changed
.vertexShaderConstantsB
|= (1 << i
);
2874 if (!This
->isRecordingState
) IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
2879 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantB(
2880 IWineD3DDevice
*iface
,
2885 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2886 int cnt
= min(count
, MAX_CONST_B
- start
);
2888 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2889 iface
, dstData
, start
, count
);
2891 if (dstData
== NULL
|| cnt
< 0)
2892 return WINED3DERR_INVALIDCALL
;
2894 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantB
[start
], cnt
* sizeof(BOOL
));
2898 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantI(
2899 IWineD3DDevice
*iface
,
2904 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2905 unsigned int i
, cnt
= min(count
, MAX_CONST_I
- start
);
2907 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2908 iface
, srcData
, start
, count
);
2910 if (!srcData
|| start
>= MAX_CONST_I
) return WINED3DERR_INVALIDCALL
;
2912 memcpy(&This
->updateStateBlock
->vertexShaderConstantI
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
2913 for (i
= 0; i
< cnt
; i
++)
2914 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
2915 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
2917 for (i
= start
; i
< cnt
+ start
; ++i
) {
2918 This
->updateStateBlock
->changed
.vertexShaderConstantsI
|= (1 << i
);
2921 if (!This
->isRecordingState
) IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
2926 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantI(
2927 IWineD3DDevice
*iface
,
2932 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2933 int cnt
= min(count
, MAX_CONST_I
- start
);
2935 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2936 iface
, dstData
, start
, count
);
2938 if (dstData
== NULL
|| ((signed int) MAX_CONST_I
- (signed int) start
) <= (signed int) 0)
2939 return WINED3DERR_INVALIDCALL
;
2941 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantI
[start
* 4], cnt
* sizeof(int) * 4);
2945 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantF(
2946 IWineD3DDevice
*iface
,
2948 CONST
float *srcData
,
2951 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2954 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2955 iface
, srcData
, start
, count
);
2957 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
2958 if (srcData
== NULL
|| start
+ count
> This
->d3d_vshader_constantF
|| start
> This
->d3d_vshader_constantF
)
2959 return WINED3DERR_INVALIDCALL
;
2961 memcpy(&This
->updateStateBlock
->vertexShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
2963 for (i
= 0; i
< count
; i
++)
2964 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
2965 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
2968 if (!This
->isRecordingState
)
2970 This
->shader_backend
->shader_update_float_vertex_constants(iface
, start
, count
);
2971 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
2974 memset(This
->updateStateBlock
->changed
.vertexShaderConstantsF
+ start
, 1,
2975 sizeof(*This
->updateStateBlock
->changed
.vertexShaderConstantsF
) * count
);
2980 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantF(
2981 IWineD3DDevice
*iface
,
2986 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2987 int cnt
= min(count
, This
->d3d_vshader_constantF
- start
);
2989 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2990 iface
, dstData
, start
, count
);
2992 if (dstData
== NULL
|| cnt
< 0)
2993 return WINED3DERR_INVALIDCALL
;
2995 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantF
[start
* 4], cnt
* sizeof(float) * 4);
2999 static inline void markTextureStagesDirty(IWineD3DDeviceImpl
*This
, DWORD stage
) {
3001 for(i
= 0; i
<= WINED3D_HIGHEST_TEXTURE_STATE
; ++i
)
3003 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, i
));
3007 static void device_map_stage(IWineD3DDeviceImpl
*This
, DWORD stage
, DWORD unit
)
3009 DWORD i
= This
->rev_tex_unit_map
[unit
];
3010 DWORD j
= This
->texUnitMap
[stage
];
3012 This
->texUnitMap
[stage
] = unit
;
3013 if (i
!= WINED3D_UNMAPPED_STAGE
&& i
!= stage
)
3015 This
->texUnitMap
[i
] = WINED3D_UNMAPPED_STAGE
;
3018 This
->rev_tex_unit_map
[unit
] = stage
;
3019 if (j
!= WINED3D_UNMAPPED_STAGE
&& j
!= unit
)
3021 This
->rev_tex_unit_map
[j
] = WINED3D_UNMAPPED_STAGE
;
3025 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl
*This
) {
3028 This
->fixed_function_usage_map
= 0;
3029 for (i
= 0; i
< MAX_TEXTURES
; ++i
) {
3030 WINED3DTEXTUREOP color_op
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLOROP
];
3031 WINED3DTEXTUREOP alpha_op
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAOP
];
3032 DWORD color_arg1
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG1
] & WINED3DTA_SELECTMASK
;
3033 DWORD color_arg2
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG2
] & WINED3DTA_SELECTMASK
;
3034 DWORD color_arg3
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG0
] & WINED3DTA_SELECTMASK
;
3035 DWORD alpha_arg1
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG1
] & WINED3DTA_SELECTMASK
;
3036 DWORD alpha_arg2
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG2
] & WINED3DTA_SELECTMASK
;
3037 DWORD alpha_arg3
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG0
] & WINED3DTA_SELECTMASK
;
3039 if (color_op
== WINED3DTOP_DISABLE
) {
3040 /* Not used, and disable higher stages */
3044 if (((color_arg1
== WINED3DTA_TEXTURE
) && color_op
!= WINED3DTOP_SELECTARG2
)
3045 || ((color_arg2
== WINED3DTA_TEXTURE
) && color_op
!= WINED3DTOP_SELECTARG1
)
3046 || ((color_arg3
== WINED3DTA_TEXTURE
) && (color_op
== WINED3DTOP_MULTIPLYADD
|| color_op
== WINED3DTOP_LERP
))
3047 || ((alpha_arg1
== WINED3DTA_TEXTURE
) && alpha_op
!= WINED3DTOP_SELECTARG2
)
3048 || ((alpha_arg2
== WINED3DTA_TEXTURE
) && alpha_op
!= WINED3DTOP_SELECTARG1
)
3049 || ((alpha_arg3
== WINED3DTA_TEXTURE
) && (alpha_op
== WINED3DTOP_MULTIPLYADD
|| alpha_op
== WINED3DTOP_LERP
))) {
3050 This
->fixed_function_usage_map
|= (1 << i
);
3053 if ((color_op
== WINED3DTOP_BUMPENVMAP
|| color_op
== WINED3DTOP_BUMPENVMAPLUMINANCE
) && i
< MAX_TEXTURES
- 1) {
3054 This
->fixed_function_usage_map
|= (1 << (i
+ 1));
3059 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl
*This
) {
3060 unsigned int i
, tex
;
3063 device_update_fixed_function_usage_map(This
);
3064 ffu_map
= This
->fixed_function_usage_map
;
3066 if (This
->max_ffp_textures
== This
->max_ffp_texture_stages
||
3067 This
->stateBlock
->lowest_disabled_stage
<= This
->max_ffp_textures
) {
3068 for (i
= 0; ffu_map
; ffu_map
>>= 1, ++i
)
3070 if (!(ffu_map
& 1)) continue;
3072 if (This
->texUnitMap
[i
] != i
) {
3073 device_map_stage(This
, i
, i
);
3074 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3075 markTextureStagesDirty(This
, i
);
3081 /* Now work out the mapping */
3083 for (i
= 0; ffu_map
; ffu_map
>>= 1, ++i
)
3085 if (!(ffu_map
& 1)) continue;
3087 if (This
->texUnitMap
[i
] != tex
) {
3088 device_map_stage(This
, i
, tex
);
3089 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3090 markTextureStagesDirty(This
, i
);
3097 static void device_map_psamplers(IWineD3DDeviceImpl
*This
) {
3098 const WINED3DSAMPLER_TEXTURE_TYPE
*sampler_type
=
3099 ((IWineD3DPixelShaderImpl
*)This
->stateBlock
->pixelShader
)->baseShader
.reg_maps
.sampler_type
;
3102 for (i
= 0; i
< MAX_FRAGMENT_SAMPLERS
; ++i
) {
3103 if (sampler_type
[i
] && This
->texUnitMap
[i
] != i
)
3105 device_map_stage(This
, i
, i
);
3106 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3107 if (i
< MAX_TEXTURES
) {
3108 markTextureStagesDirty(This
, i
);
3114 static BOOL
device_unit_free_for_vs(IWineD3DDeviceImpl
*This
, const DWORD
*pshader_sampler_tokens
,
3115 const DWORD
*vshader_sampler_tokens
, DWORD unit
)
3117 DWORD current_mapping
= This
->rev_tex_unit_map
[unit
];
3119 /* Not currently used */
3120 if (current_mapping
== WINED3D_UNMAPPED_STAGE
) return TRUE
;
3122 if (current_mapping
< MAX_FRAGMENT_SAMPLERS
) {
3123 /* Used by a fragment sampler */
3125 if (!pshader_sampler_tokens
) {
3126 /* No pixel shader, check fixed function */
3127 return current_mapping
>= MAX_TEXTURES
|| !(This
->fixed_function_usage_map
& (1 << current_mapping
));
3130 /* Pixel shader, check the shader's sampler map */
3131 return !pshader_sampler_tokens
[current_mapping
];
3134 /* Used by a vertex sampler */
3135 return !vshader_sampler_tokens
[current_mapping
- MAX_FRAGMENT_SAMPLERS
];
3138 static void device_map_vsamplers(IWineD3DDeviceImpl
*This
, BOOL ps
) {
3139 const WINED3DSAMPLER_TEXTURE_TYPE
*vshader_sampler_type
=
3140 ((IWineD3DVertexShaderImpl
*)This
->stateBlock
->vertexShader
)->baseShader
.reg_maps
.sampler_type
;
3141 const WINED3DSAMPLER_TEXTURE_TYPE
*pshader_sampler_type
= NULL
;
3142 int start
= min(MAX_COMBINED_SAMPLERS
, This
->adapter
->gl_info
.limits
.combined_samplers
) - 1;
3146 IWineD3DPixelShaderImpl
*pshader
= (IWineD3DPixelShaderImpl
*)This
->stateBlock
->pixelShader
;
3148 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3149 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3150 pshader_sampler_type
= pshader
->baseShader
.reg_maps
.sampler_type
;
3153 for (i
= 0; i
< MAX_VERTEX_SAMPLERS
; ++i
) {
3154 DWORD vsampler_idx
= i
+ MAX_FRAGMENT_SAMPLERS
;
3155 if (vshader_sampler_type
[i
])
3157 if (This
->texUnitMap
[vsampler_idx
] != WINED3D_UNMAPPED_STAGE
)
3159 /* Already mapped somewhere */
3163 while (start
>= 0) {
3164 if (device_unit_free_for_vs(This
, pshader_sampler_type
, vshader_sampler_type
, start
))
3166 device_map_stage(This
, vsampler_idx
, start
);
3167 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(vsampler_idx
));
3179 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl
*This
) {
3180 BOOL vs
= use_vs(This
->stateBlock
);
3181 BOOL ps
= use_ps(This
->stateBlock
);
3184 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3185 * that would be really messy and require shader recompilation
3186 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3187 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3190 device_map_psamplers(This
);
3192 device_map_fixed_function_samplers(This
);
3196 device_map_vsamplers(This
, ps
);
3200 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
*pShader
) {
3201 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3202 IWineD3DPixelShader
*oldShader
= This
->updateStateBlock
->pixelShader
;
3203 This
->updateStateBlock
->pixelShader
= pShader
;
3204 This
->updateStateBlock
->changed
.pixelShader
= TRUE
;
3206 /* Handle recording of state blocks */
3207 if (This
->isRecordingState
) {
3208 TRACE("Recording... not performing anything\n");
3211 if (This
->isRecordingState
) {
3212 TRACE("Recording... not performing anything\n");
3213 if(pShader
) IWineD3DPixelShader_AddRef(pShader
);
3214 if(oldShader
) IWineD3DPixelShader_Release(oldShader
);
3218 if(pShader
== oldShader
) {
3219 TRACE("App is setting the old pixel shader over, nothing to do\n");
3223 if(pShader
) IWineD3DPixelShader_AddRef(pShader
);
3224 if(oldShader
) IWineD3DPixelShader_Release(oldShader
);
3226 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
3227 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADER
);
3232 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
**ppShader
) {
3233 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3235 if (NULL
== ppShader
) {
3236 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This
);
3237 return WINED3DERR_INVALIDCALL
;
3240 *ppShader
= This
->stateBlock
->pixelShader
;
3241 if (NULL
!= *ppShader
) {
3242 IWineD3DPixelShader_AddRef(*ppShader
);
3244 TRACE("(%p) : returning %p\n", This
, *ppShader
);
3248 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantB(
3249 IWineD3DDevice
*iface
,
3251 CONST BOOL
*srcData
,
3254 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3255 unsigned int i
, cnt
= min(count
, MAX_CONST_B
- start
);
3257 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3258 iface
, srcData
, start
, count
);
3260 if (!srcData
|| start
>= MAX_CONST_B
) return WINED3DERR_INVALIDCALL
;
3262 memcpy(&This
->updateStateBlock
->pixelShaderConstantB
[start
], srcData
, cnt
* sizeof(BOOL
));
3263 for (i
= 0; i
< cnt
; i
++)
3264 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
3266 for (i
= start
; i
< cnt
+ start
; ++i
) {
3267 This
->updateStateBlock
->changed
.pixelShaderConstantsB
|= (1 << i
);
3270 if (!This
->isRecordingState
) IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3275 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantB(
3276 IWineD3DDevice
*iface
,
3281 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3282 int cnt
= min(count
, MAX_CONST_B
- start
);
3284 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3285 iface
, dstData
, start
, count
);
3287 if (dstData
== NULL
|| cnt
< 0)
3288 return WINED3DERR_INVALIDCALL
;
3290 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantB
[start
], cnt
* sizeof(BOOL
));
3294 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantI(
3295 IWineD3DDevice
*iface
,
3300 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3301 unsigned int i
, cnt
= min(count
, MAX_CONST_I
- start
);
3303 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3304 iface
, srcData
, start
, count
);
3306 if (!srcData
|| start
>= MAX_CONST_I
) return WINED3DERR_INVALIDCALL
;
3308 memcpy(&This
->updateStateBlock
->pixelShaderConstantI
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
3309 for (i
= 0; i
< cnt
; i
++)
3310 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
3311 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3313 for (i
= start
; i
< cnt
+ start
; ++i
) {
3314 This
->updateStateBlock
->changed
.pixelShaderConstantsI
|= (1 << i
);
3317 if (!This
->isRecordingState
) IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3322 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantI(
3323 IWineD3DDevice
*iface
,
3328 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3329 int cnt
= min(count
, MAX_CONST_I
- start
);
3331 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3332 iface
, dstData
, start
, count
);
3334 if (dstData
== NULL
|| cnt
< 0)
3335 return WINED3DERR_INVALIDCALL
;
3337 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantI
[start
* 4], cnt
* sizeof(int) * 4);
3341 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantF(
3342 IWineD3DDevice
*iface
,
3344 CONST
float *srcData
,
3347 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3350 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3351 iface
, srcData
, start
, count
);
3353 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3354 if (srcData
== NULL
|| start
+ count
> This
->d3d_pshader_constantF
|| start
> This
->d3d_pshader_constantF
)
3355 return WINED3DERR_INVALIDCALL
;
3357 memcpy(&This
->updateStateBlock
->pixelShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
3359 for (i
= 0; i
< count
; i
++)
3360 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
3361 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3364 if (!This
->isRecordingState
)
3366 This
->shader_backend
->shader_update_float_pixel_constants(iface
, start
, count
);
3367 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3370 memset(This
->updateStateBlock
->changed
.pixelShaderConstantsF
+ start
, 1,
3371 sizeof(*This
->updateStateBlock
->changed
.pixelShaderConstantsF
) * count
);
3376 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantF(
3377 IWineD3DDevice
*iface
,
3382 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3383 int cnt
= min(count
, This
->d3d_pshader_constantF
- start
);
3385 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3386 iface
, dstData
, start
, count
);
3388 if (dstData
== NULL
|| cnt
< 0)
3389 return WINED3DERR_INVALIDCALL
;
3391 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantF
[start
* 4], cnt
* sizeof(float) * 4);
3395 /* Context activation is done by the caller. */
3396 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3397 static HRESULT
process_vertices_strided(IWineD3DDeviceImpl
*This
, DWORD dwDestIndex
, DWORD dwCount
,
3398 const struct wined3d_stream_info
*stream_info
, struct wined3d_buffer
*dest
, DWORD dwFlags
,
3401 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
3402 char *dest_ptr
, *dest_conv
= NULL
, *dest_conv_addr
= NULL
;
3405 WINED3DMATRIX mat
, proj_mat
, view_mat
, world_mat
;
3409 if (stream_info
->use_map
& (1 << WINED3D_FFP_NORMAL
))
3411 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3414 if (!(stream_info
->use_map
& (1 << WINED3D_FFP_POSITION
)))
3416 ERR("Source has no position mask\n");
3417 return WINED3DERR_INVALIDCALL
;
3420 /* We might access VBOs from this code, so hold the lock */
3423 if (dest
->resource
.allocatedMemory
== NULL
) {
3424 buffer_get_sysmem(dest
);
3427 /* Get a pointer into the destination vbo(create one if none exists) and
3428 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3430 if (!dest
->buffer_object
&& gl_info
->supported
[ARB_VERTEX_BUFFER_OBJECT
])
3432 dest
->flags
|= WINED3D_BUFFER_CREATEBO
;
3433 IWineD3DBuffer_PreLoad((IWineD3DBuffer
*)dest
);
3436 if (dest
->buffer_object
)
3438 unsigned char extrabytes
= 0;
3439 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3440 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3441 * this may write 4 extra bytes beyond the area that should be written
3443 if(DestFVF
== WINED3DFVF_XYZ
) extrabytes
= 4;
3444 dest_conv_addr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwCount
* get_flexible_vertex_size(DestFVF
) + extrabytes
);
3445 if(!dest_conv_addr
) {
3446 ERR("Out of memory\n");
3447 /* Continue without storing converted vertices */
3449 dest_conv
= dest_conv_addr
;
3453 * a) WINED3DRS_CLIPPING is enabled
3454 * b) WINED3DVOP_CLIP is passed
3456 if(This
->stateBlock
->renderState
[WINED3DRS_CLIPPING
]) {
3457 static BOOL warned
= FALSE
;
3459 * The clipping code is not quite correct. Some things need
3460 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3461 * so disable clipping for now.
3462 * (The graphics in Half-Life are broken, and my processvertices
3463 * test crashes with IDirect3DDevice3)
3469 FIXME("Clipping is broken and disabled for now\n");
3471 } else doClip
= FALSE
;
3472 dest_ptr
= ((char *) buffer_get_sysmem(dest
)) + dwDestIndex
* get_flexible_vertex_size(DestFVF
);
3474 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
3477 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
3478 WINED3DTS_PROJECTION
,
3480 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
3481 WINED3DTS_WORLDMATRIX(0),
3484 TRACE("View mat:\n");
3485 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
);
3486 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
);
3487 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
);
3488 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
);
3490 TRACE("Proj mat:\n");
3491 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
);
3492 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
);
3493 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
);
3494 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
);
3496 TRACE("World mat:\n");
3497 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
);
3498 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
);
3499 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
);
3500 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
);
3502 /* Get the viewport */
3503 IWineD3DDevice_GetViewport( (IWineD3DDevice
*) This
, &vp
);
3504 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3505 vp
.X
, vp
.Y
, vp
.Width
, vp
.Height
, vp
.MinZ
, vp
.MaxZ
);
3507 multiply_matrix(&mat
,&view_mat
,&world_mat
);
3508 multiply_matrix(&mat
,&proj_mat
,&mat
);
3510 numTextures
= (DestFVF
& WINED3DFVF_TEXCOUNT_MASK
) >> WINED3DFVF_TEXCOUNT_SHIFT
;
3512 for (i
= 0; i
< dwCount
; i
+= 1) {
3513 unsigned int tex_index
;
3515 if ( ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZ
) ||
3516 ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) ) {
3517 /* The position first */
3518 const struct wined3d_stream_info_element
*element
= &stream_info
->elements
[WINED3D_FFP_POSITION
];
3519 const float *p
= (const float *)(element
->data
+ i
* element
->stride
);
3521 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p
[0], p
[1], p
[2]);
3523 /* Multiplication with world, view and projection matrix */
3524 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
);
3525 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
);
3526 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
);
3527 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
);
3529 TRACE("x=%f y=%f z=%f rhw=%f\n", x
, y
, z
, rhw
);
3531 /* WARNING: The following things are taken from d3d7 and were not yet checked
3532 * against d3d8 or d3d9!
3535 /* Clipping conditions: From msdn
3537 * A vertex is clipped if it does not match the following requirements
3541 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3543 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3544 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3549 ( (-rhw
-eps
< x
) && (-rhw
-eps
< y
) && ( -eps
< z
) &&
3550 (x
<= rhw
+ eps
) && (y
<= rhw
+ eps
) && (z
<= rhw
+ eps
) &&
3553 /* "Normal" viewport transformation (not clipped)
3554 * 1) The values are divided by rhw
3555 * 2) The y axis is negative, so multiply it with -1
3556 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3557 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3558 * 4) Multiply x with Width/2 and add Width/2
3559 * 5) The same for the height
3560 * 6) Add the viewpoint X and Y to the 2D coordinates and
3561 * The minimum Z value to z
3562 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3564 * Well, basically it's simply a linear transformation into viewport
3576 z
*= vp
.MaxZ
- vp
.MinZ
;
3578 x
+= vp
.Width
/ 2 + vp
.X
;
3579 y
+= vp
.Height
/ 2 + vp
.Y
;
3584 /* That vertex got clipped
3585 * Contrary to OpenGL it is not dropped completely, it just
3586 * undergoes a different calculation.
3588 TRACE("Vertex got clipped\n");
3595 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3596 * outside of the main vertex buffer memory. That needs some more
3601 TRACE("Writing (%f %f %f) %f\n", x
, y
, z
, rhw
);
3604 ( (float *) dest_ptr
)[0] = x
;
3605 ( (float *) dest_ptr
)[1] = y
;
3606 ( (float *) dest_ptr
)[2] = z
;
3607 ( (float *) dest_ptr
)[3] = rhw
; /* SIC, see ddraw test! */
3609 dest_ptr
+= 3 * sizeof(float);
3611 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
3612 dest_ptr
+= sizeof(float);
3617 ( (float *) dest_conv
)[0] = x
* w
;
3618 ( (float *) dest_conv
)[1] = y
* w
;
3619 ( (float *) dest_conv
)[2] = z
* w
;
3620 ( (float *) dest_conv
)[3] = w
;
3622 dest_conv
+= 3 * sizeof(float);
3624 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
3625 dest_conv
+= sizeof(float);
3629 if (DestFVF
& WINED3DFVF_PSIZE
) {
3630 dest_ptr
+= sizeof(DWORD
);
3631 if(dest_conv
) dest_conv
+= sizeof(DWORD
);
3633 if (DestFVF
& WINED3DFVF_NORMAL
) {
3634 const struct wined3d_stream_info_element
*element
= &stream_info
->elements
[WINED3D_FFP_NORMAL
];
3635 const float *normal
= (const float *)(element
->data
+ i
* element
->stride
);
3636 /* AFAIK this should go into the lighting information */
3637 FIXME("Didn't expect the destination to have a normal\n");
3638 copy_and_next(dest_ptr
, normal
, 3 * sizeof(float));
3640 copy_and_next(dest_conv
, normal
, 3 * sizeof(float));
3644 if (DestFVF
& WINED3DFVF_DIFFUSE
) {
3645 const struct wined3d_stream_info_element
*element
= &stream_info
->elements
[WINED3D_FFP_DIFFUSE
];
3646 const DWORD
*color_d
= (const DWORD
*)(element
->data
+ i
* element
->stride
);
3647 if (!(stream_info
->use_map
& (1 << WINED3D_FFP_DIFFUSE
)))
3649 static BOOL warned
= FALSE
;
3652 ERR("No diffuse color in source, but destination has one\n");
3656 *( (DWORD
*) dest_ptr
) = 0xffffffff;
3657 dest_ptr
+= sizeof(DWORD
);
3660 *( (DWORD
*) dest_conv
) = 0xffffffff;
3661 dest_conv
+= sizeof(DWORD
);
3665 copy_and_next(dest_ptr
, color_d
, sizeof(DWORD
));
3667 *( (DWORD
*) dest_conv
) = (*color_d
& 0xff00ff00) ; /* Alpha + green */
3668 *( (DWORD
*) dest_conv
) |= (*color_d
& 0x00ff0000) >> 16; /* Red */
3669 *( (DWORD
*) dest_conv
) |= (*color_d
& 0xff0000ff) << 16; /* Blue */
3670 dest_conv
+= sizeof(DWORD
);
3675 if (DestFVF
& WINED3DFVF_SPECULAR
)
3677 /* What's the color value in the feedback buffer? */
3678 const struct wined3d_stream_info_element
*element
= &stream_info
->elements
[WINED3D_FFP_SPECULAR
];
3679 const DWORD
*color_s
= (const DWORD
*)(element
->data
+ i
* element
->stride
);
3680 if (!(stream_info
->use_map
& (1 << WINED3D_FFP_SPECULAR
)))
3682 static BOOL warned
= FALSE
;
3685 ERR("No specular color in source, but destination has one\n");
3689 *( (DWORD
*) dest_ptr
) = 0xFF000000;
3690 dest_ptr
+= sizeof(DWORD
);
3693 *( (DWORD
*) dest_conv
) = 0xFF000000;
3694 dest_conv
+= sizeof(DWORD
);
3698 copy_and_next(dest_ptr
, color_s
, sizeof(DWORD
));
3700 *( (DWORD
*) dest_conv
) = (*color_s
& 0xff00ff00) ; /* Alpha + green */
3701 *( (DWORD
*) dest_conv
) |= (*color_s
& 0x00ff0000) >> 16; /* Red */
3702 *( (DWORD
*) dest_conv
) |= (*color_s
& 0xff0000ff) << 16; /* Blue */
3703 dest_conv
+= sizeof(DWORD
);
3708 for (tex_index
= 0; tex_index
< numTextures
; tex_index
++) {
3709 const struct wined3d_stream_info_element
*element
= &stream_info
->elements
[WINED3D_FFP_TEXCOORD0
+ tex_index
];
3710 const float *tex_coord
= (const float *)(element
->data
+ i
* element
->stride
);
3711 if (!(stream_info
->use_map
& (1 << (WINED3D_FFP_TEXCOORD0
+ tex_index
))))
3713 ERR("No source texture, but destination requests one\n");
3714 dest_ptr
+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
3715 if(dest_conv
) dest_conv
+= GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
3718 copy_and_next(dest_ptr
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
3720 copy_and_next(dest_conv
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
3727 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, dest
->buffer_object
));
3728 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3729 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB
, dwDestIndex
* get_flexible_vertex_size(DestFVF
),
3730 dwCount
* get_flexible_vertex_size(DestFVF
),
3732 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3733 HeapFree(GetProcessHeap(), 0, dest_conv_addr
);
3740 #undef copy_and_next
3742 static HRESULT WINAPI
IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice
*iface
, UINT SrcStartIndex
, UINT DestIndex
,
3743 UINT VertexCount
, IWineD3DBuffer
*pDestBuffer
, IWineD3DVertexDeclaration
*pVertexDecl
, DWORD Flags
,
3746 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3747 struct wined3d_stream_info stream_info
;
3748 struct wined3d_context
*context
;
3749 BOOL vbo
= FALSE
, streamWasUP
= This
->stateBlock
->streamIsUP
;
3752 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This
, SrcStartIndex
, DestIndex
, VertexCount
, pDestBuffer
, pVertexDecl
, Flags
);
3755 ERR("Output vertex declaration not implemented yet\n");
3758 /* Need any context to write to the vbo. */
3759 context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
3761 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3762 * control the streamIsUP flag, thus restore it afterwards.
3764 This
->stateBlock
->streamIsUP
= FALSE
;
3765 device_stream_info_from_declaration(This
, FALSE
, &stream_info
, &vbo
);
3766 This
->stateBlock
->streamIsUP
= streamWasUP
;
3768 if(vbo
|| SrcStartIndex
) {
3770 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
3771 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
3773 * Also get the start index in, but only loop over all elements if there's something to add at all.
3775 for (i
= 0; i
< (sizeof(stream_info
.elements
) / sizeof(*stream_info
.elements
)); ++i
)
3777 struct wined3d_stream_info_element
*e
;
3779 if (!(stream_info
.use_map
& (1 << i
))) continue;
3781 e
= &stream_info
.elements
[i
];
3782 if (e
->buffer_object
)
3784 struct wined3d_buffer
*vb
= (struct wined3d_buffer
*)This
->stateBlock
->streamSource
[e
->stream_idx
];
3785 e
->buffer_object
= 0;
3786 e
->data
= (BYTE
*)((unsigned long)e
->data
+ (unsigned long)buffer_get_sysmem(vb
));
3788 GL_EXTCALL(glDeleteBuffersARB(1, &vb
->buffer_object
));
3789 vb
->buffer_object
= 0;
3792 if (e
->data
) e
->data
+= e
->stride
* SrcStartIndex
;
3796 hr
= process_vertices_strided(This
, DestIndex
, VertexCount
, &stream_info
,
3797 (struct wined3d_buffer
*)pDestBuffer
, Flags
, DestFVF
);
3799 context_release(context
);
3805 * Get / Set Texture Stage States
3806 * TODO: Verify against dx9 definitions
3808 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD Value
) {
3809 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3810 DWORD oldValue
= This
->updateStateBlock
->textureState
[Stage
][Type
];
3812 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This
, Stage
, debug_d3dtexturestate(Type
), Type
, Value
);
3814 if (Stage
>= MAX_TEXTURES
) {
3815 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage
, MAX_TEXTURES
- 1);
3819 This
->updateStateBlock
->changed
.textureState
[Stage
] |= 1 << Type
;
3820 This
->updateStateBlock
->textureState
[Stage
][Type
] = Value
;
3822 if (This
->isRecordingState
) {
3823 TRACE("Recording... not performing anything\n");
3827 /* Checked after the assignments to allow proper stateblock recording */
3828 if(oldValue
== Value
) {
3829 TRACE("App is setting the old value over, nothing to do\n");
3833 if(Stage
> This
->stateBlock
->lowest_disabled_stage
&&
3834 This
->StateTable
[STATE_TEXTURESTAGE(0, Type
)].representative
== STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP
)) {
3835 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3836 * Changes in other states are important on disabled stages too
3841 if(Type
== WINED3DTSS_COLOROP
) {
3844 if(Value
== WINED3DTOP_DISABLE
&& oldValue
!= WINED3DTOP_DISABLE
) {
3845 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3846 * they have to be disabled
3848 * The current stage is dirtified below.
3850 for(i
= Stage
+ 1; i
< This
->stateBlock
->lowest_disabled_stage
; i
++) {
3851 TRACE("Additionally dirtifying stage %u\n", i
);
3852 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
3854 This
->stateBlock
->lowest_disabled_stage
= Stage
;
3855 TRACE("New lowest disabled: %u\n", Stage
);
3856 } else if(Value
!= WINED3DTOP_DISABLE
&& oldValue
== WINED3DTOP_DISABLE
) {
3857 /* Previously disabled stage enabled. Stages above it may need enabling
3858 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3859 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3861 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3864 for (i
= Stage
+ 1; i
< This
->adapter
->gl_info
.limits
.texture_stages
; ++i
)
3866 if(This
->updateStateBlock
->textureState
[i
][WINED3DTSS_COLOROP
] == WINED3DTOP_DISABLE
) {
3869 TRACE("Additionally dirtifying stage %u due to enable\n", i
);
3870 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
3872 This
->stateBlock
->lowest_disabled_stage
= i
;
3873 TRACE("New lowest disabled: %u\n", i
);
3877 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, Type
));
3882 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD
* pValue
) {
3883 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3884 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This
, Stage
, Type
, This
->updateStateBlock
->textureState
[Stage
][Type
]);
3885 *pValue
= This
->updateStateBlock
->textureState
[Stage
][Type
];
3892 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTexture(IWineD3DDevice
*iface
,
3893 DWORD stage
, IWineD3DBaseTexture
*texture
)
3895 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3896 IWineD3DBaseTexture
*prev
;
3898 TRACE("iface %p, stage %u, texture %p.\n", iface
, stage
, texture
);
3900 if (stage
>= WINED3DVERTEXTEXTURESAMPLER0
&& stage
<= WINED3DVERTEXTEXTURESAMPLER3
)
3901 stage
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
3903 /* Windows accepts overflowing this array... we do not. */
3904 if (stage
>= sizeof(This
->stateBlock
->textures
) / sizeof(*This
->stateBlock
->textures
))
3906 WARN("Ignoring invalid stage %u.\n", stage
);
3910 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
3911 if (texture
&& ((IWineD3DTextureImpl
*)texture
)->resource
.pool
== WINED3DPOOL_SCRATCH
)
3913 WARN("Rejecting attempt to set scratch texture.\n");
3914 return WINED3DERR_INVALIDCALL
;
3917 This
->updateStateBlock
->changed
.textures
|= 1 << stage
;
3919 prev
= This
->updateStateBlock
->textures
[stage
];
3920 TRACE("Previous texture %p.\n", prev
);
3922 if (texture
== prev
)
3924 TRACE("App is setting the same texture again, nothing to do.\n");
3928 TRACE("Setting new texture to %p.\n", texture
);
3929 This
->updateStateBlock
->textures
[stage
] = texture
;
3931 if (This
->isRecordingState
)
3933 TRACE("Recording... not performing anything\n");
3935 if (texture
) IWineD3DBaseTexture_AddRef(texture
);
3936 if (prev
) IWineD3DBaseTexture_Release(prev
);
3943 IWineD3DBaseTextureImpl
*t
= (IWineD3DBaseTextureImpl
*)texture
;
3944 LONG bind_count
= InterlockedIncrement(&t
->baseTexture
.bindCount
);
3945 UINT dimensions
= IWineD3DBaseTexture_GetTextureDimensions(texture
);
3947 IWineD3DBaseTexture_AddRef(texture
);
3949 if (!prev
|| dimensions
!= IWineD3DBaseTexture_GetTextureDimensions(prev
))
3951 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADER
);
3954 if (!prev
&& stage
< MAX_TEXTURES
)
3956 /* The source arguments for color and alpha ops have different
3957 * meanings when a NULL texture is bound, so the COLOROP and
3958 * ALPHAOP have to be dirtified. */
3959 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, WINED3DTSS_COLOROP
));
3960 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, WINED3DTSS_ALPHAOP
));
3963 if (bind_count
== 1) t
->baseTexture
.sampler
= stage
;
3968 IWineD3DBaseTextureImpl
*t
= (IWineD3DBaseTextureImpl
*)prev
;
3969 LONG bind_count
= InterlockedDecrement(&t
->baseTexture
.bindCount
);
3971 IWineD3DBaseTexture_Release(prev
);
3973 if (!texture
&& stage
< MAX_TEXTURES
)
3975 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, WINED3DTSS_COLOROP
));
3976 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, WINED3DTSS_ALPHAOP
));
3979 if (bind_count
&& t
->baseTexture
.sampler
== stage
)
3983 /* Search for other stages the texture is bound to. Shouldn't
3984 * happen if applications bind textures to a single stage only. */
3985 TRACE("Searching for other stages the texture is bound to.\n");
3986 for (i
= 0; i
< MAX_COMBINED_SAMPLERS
; ++i
)
3988 if (This
->updateStateBlock
->textures
[i
] == prev
)
3990 TRACE("Texture is also bound to stage %u.\n", i
);
3991 t
->baseTexture
.sampler
= i
;
3998 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(stage
));
4003 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTexture(IWineD3DDevice
*iface
, DWORD Stage
, IWineD3DBaseTexture
** ppTexture
) {
4004 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4006 TRACE("(%p) : Stage %#x, ppTexture %p\n", This
, Stage
, ppTexture
);
4008 if (Stage
>= WINED3DVERTEXTEXTURESAMPLER0
&& Stage
<= WINED3DVERTEXTEXTURESAMPLER3
) {
4009 Stage
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
4012 if (Stage
>= sizeof(This
->stateBlock
->textures
)/sizeof(This
->stateBlock
->textures
[0])) {
4013 ERR("Current stage overflows textures array (stage %d)\n", Stage
);
4014 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
4017 *ppTexture
=This
->stateBlock
->textures
[Stage
];
4019 IWineD3DBaseTexture_AddRef(*ppTexture
);
4021 TRACE("(%p) : Returning %p\n", This
, *ppTexture
);
4029 static HRESULT WINAPI
IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice
*iface
, UINT swapchain_idx
,
4030 UINT backbuffer_idx
, WINED3DBACKBUFFER_TYPE backbuffer_type
, IWineD3DSurface
**backbuffer
)
4032 IWineD3DSwapChain
*swapchain
;
4035 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4036 iface
, swapchain_idx
, backbuffer_idx
, backbuffer_type
, backbuffer
);
4038 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, swapchain_idx
, &swapchain
);
4041 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx
, hr
);
4045 hr
= IWineD3DSwapChain_GetBackBuffer(swapchain
, backbuffer_idx
, backbuffer_type
, backbuffer
);
4046 IWineD3DSwapChain_Release(swapchain
);
4049 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx
, hr
);
4056 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice
*iface
, WINED3DCAPS
* pCaps
) {
4057 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4058 WARN("(%p) : stub, calling idirect3d for now\n", This
);
4059 return IWineD3D_GetDeviceCaps(This
->wined3d
, This
->adapter
->ordinal
, This
->devType
, pCaps
);
4062 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DDISPLAYMODE
* pMode
) {
4063 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4064 IWineD3DSwapChain
*swapChain
;
4067 if(iSwapChain
> 0) {
4068 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
4069 if (hr
== WINED3D_OK
) {
4070 hr
= IWineD3DSwapChain_GetDisplayMode(swapChain
, pMode
);
4071 IWineD3DSwapChain_Release(swapChain
);
4073 FIXME("(%p) Error getting display mode\n", This
);
4076 /* Don't read the real display mode,
4077 but return the stored mode instead. X11 can't change the color
4078 depth, and some apps are pretty angry if they SetDisplayMode from
4079 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4081 Also don't relay to the swapchain because with ddraw it's possible
4082 that there isn't a swapchain at all */
4083 pMode
->Width
= This
->ddraw_width
;
4084 pMode
->Height
= This
->ddraw_height
;
4085 pMode
->Format
= This
->ddraw_format
;
4086 pMode
->RefreshRate
= 0;
4094 * Stateblock related functions
4097 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice
*iface
) {
4098 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4099 IWineD3DStateBlock
*stateblock
;
4102 TRACE("(%p)\n", This
);
4104 if (This
->isRecordingState
) return WINED3DERR_INVALIDCALL
;
4106 hr
= IWineD3DDeviceImpl_CreateStateBlock(iface
, WINED3DSBT_RECORDED
, &stateblock
, NULL
);
4107 if (FAILED(hr
)) return hr
;
4109 IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
);
4110 This
->updateStateBlock
= (IWineD3DStateBlockImpl
*)stateblock
;
4111 This
->isRecordingState
= TRUE
;
4113 TRACE("(%p) recording stateblock %p\n", This
, stateblock
);
4118 static HRESULT WINAPI
IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice
*iface
, IWineD3DStateBlock
** ppStateBlock
) {
4119 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4120 IWineD3DStateBlockImpl
*object
= This
->updateStateBlock
;
4122 if (!This
->isRecordingState
) {
4123 WARN("(%p) not recording! returning error\n", This
);
4124 *ppStateBlock
= NULL
;
4125 return WINED3DERR_INVALIDCALL
;
4128 stateblock_init_contained_states(object
);
4130 *ppStateBlock
= (IWineD3DStateBlock
*) object
;
4131 This
->isRecordingState
= FALSE
;
4132 This
->updateStateBlock
= This
->stateBlock
;
4133 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
4134 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4135 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This
, *ppStateBlock
);
4140 * Scene related functions
4142 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginScene(IWineD3DDevice
*iface
) {
4143 /* At the moment we have no need for any functionality at the beginning
4145 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4146 TRACE("(%p)\n", This
);
4149 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4150 return WINED3DERR_INVALIDCALL
;
4152 This
->inScene
= TRUE
;
4156 static HRESULT WINAPI
IWineD3DDeviceImpl_EndScene(IWineD3DDevice
*iface
)
4158 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4159 struct wined3d_context
*context
;
4161 TRACE("(%p)\n", This
);
4163 if(!This
->inScene
) {
4164 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4165 return WINED3DERR_INVALIDCALL
;
4168 context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
4169 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4171 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4173 context_release(context
);
4175 This
->inScene
= FALSE
;
4179 static HRESULT WINAPI
IWineD3DDeviceImpl_Present(IWineD3DDevice
*iface
,
4180 const RECT
*pSourceRect
, const RECT
*pDestRect
,
4181 HWND hDestWindowOverride
, const RGNDATA
*pDirtyRegion
)
4183 IWineD3DSwapChain
*swapChain
= NULL
;
4185 int swapchains
= IWineD3DDeviceImpl_GetNumberOfSwapChains(iface
);
4187 TRACE("iface %p.\n", iface
);
4189 for(i
= 0 ; i
< swapchains
; i
++) {
4191 IWineD3DDeviceImpl_GetSwapChain(iface
, i
, &swapChain
);
4192 TRACE("presentinng chain %d, %p\n", i
, swapChain
);
4193 IWineD3DSwapChain_Present(swapChain
, pSourceRect
, pDestRect
, hDestWindowOverride
, pDirtyRegion
, 0);
4194 IWineD3DSwapChain_Release(swapChain
);
4200 /* Not called from the VTable (internal subroutine) */
4201 HRESULT
IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl
*This
, IWineD3DSurfaceImpl
*target
, DWORD Count
,
4202 CONST WINED3DRECT
* pRects
, DWORD Flags
, WINED3DCOLOR Color
,
4203 float Z
, DWORD Stencil
) {
4204 GLbitfield glMask
= 0;
4206 WINED3DRECT curRect
;
4208 const WINED3DVIEWPORT
*vp
= &This
->stateBlock
->viewport
;
4209 UINT drawable_width
, drawable_height
;
4210 IWineD3DSurfaceImpl
*depth_stencil
= (IWineD3DSurfaceImpl
*) This
->stencilBufferTarget
;
4211 IWineD3DSwapChainImpl
*swapchain
= NULL
;
4212 struct wined3d_context
*context
;
4214 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4215 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4216 * for the cleared parts, and the untouched parts.
4218 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4219 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4220 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4221 * checking all this if the dest surface is in the drawable anyway.
4223 if((Flags
& WINED3DCLEAR_TARGET
) && !(target
->Flags
& SFLAG_INDRAWABLE
)) {
4225 if(vp
->X
!= 0 || vp
->Y
!= 0 ||
4226 vp
->Width
< target
->currentDesc
.Width
|| vp
->Height
< target
->currentDesc
.Height
) {
4227 IWineD3DSurface_LoadLocation((IWineD3DSurface
*) target
, SFLAG_INDRAWABLE
, NULL
);
4230 if(This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
] && (
4231 This
->stateBlock
->scissorRect
.left
> 0 || This
->stateBlock
->scissorRect
.top
> 0 ||
4232 This
->stateBlock
->scissorRect
.right
< target
->currentDesc
.Width
||
4233 This
->stateBlock
->scissorRect
.bottom
< target
->currentDesc
.Height
)) {
4234 IWineD3DSurface_LoadLocation((IWineD3DSurface
*) target
, SFLAG_INDRAWABLE
, NULL
);
4237 if(Count
> 0 && pRects
&& (
4238 pRects
[0].x1
> 0 || pRects
[0].y1
> 0 ||
4239 pRects
[0].x2
< target
->currentDesc
.Width
||
4240 pRects
[0].y2
< target
->currentDesc
.Height
)) {
4241 IWineD3DSurface_LoadLocation((IWineD3DSurface
*) target
, SFLAG_INDRAWABLE
, NULL
);
4248 context
= context_acquire(This
, (IWineD3DSurface
*)target
, CTXUSAGE_CLEAR
);
4250 target
->get_drawable_size(context
, &drawable_width
, &drawable_height
);
4254 /* Only set the values up once, as they are not changing */
4255 if (Flags
& WINED3DCLEAR_STENCIL
) {
4256 glClearStencil(Stencil
);
4257 checkGLcall("glClearStencil");
4258 glMask
= glMask
| GL_STENCIL_BUFFER_BIT
;
4259 glStencilMask(0xFFFFFFFF);
4262 if (Flags
& WINED3DCLEAR_ZBUFFER
) {
4263 DWORD location
= context
->render_offscreen
? SFLAG_DS_OFFSCREEN
: SFLAG_DS_ONSCREEN
;
4264 glDepthMask(GL_TRUE
);
4266 checkGLcall("glClearDepth");
4267 glMask
= glMask
| GL_DEPTH_BUFFER_BIT
;
4268 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ZWRITEENABLE
));
4270 if (vp
->X
!= 0 || vp
->Y
!= 0 ||
4271 vp
->Width
< depth_stencil
->currentDesc
.Width
|| vp
->Height
< depth_stencil
->currentDesc
.Height
) {
4272 surface_load_ds_location(This
->stencilBufferTarget
, context
, location
);
4274 else if (This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
] && (
4275 This
->stateBlock
->scissorRect
.left
> 0 || This
->stateBlock
->scissorRect
.top
> 0 ||
4276 This
->stateBlock
->scissorRect
.right
< depth_stencil
->currentDesc
.Width
||
4277 This
->stateBlock
->scissorRect
.bottom
< depth_stencil
->currentDesc
.Height
)) {
4278 surface_load_ds_location(This
->stencilBufferTarget
, context
, location
);
4280 else if (Count
> 0 && pRects
&& (
4281 pRects
[0].x1
> 0 || pRects
[0].y1
> 0 ||
4282 pRects
[0].x2
< depth_stencil
->currentDesc
.Width
||
4283 pRects
[0].y2
< depth_stencil
->currentDesc
.Height
)) {
4284 surface_load_ds_location(This
->stencilBufferTarget
, context
, location
);
4288 if (Flags
& WINED3DCLEAR_TARGET
) {
4289 TRACE("Clearing screen with glClear to color %x\n", Color
);
4290 glClearColor(D3DCOLOR_R(Color
),
4294 checkGLcall("glClearColor");
4296 /* Clear ALL colors! */
4297 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
4298 glMask
= glMask
| GL_COLOR_BUFFER_BIT
;
4301 vp_rect
.left
= vp
->X
;
4302 vp_rect
.top
= vp
->Y
;
4303 vp_rect
.right
= vp
->X
+ vp
->Width
;
4304 vp_rect
.bottom
= vp
->Y
+ vp
->Height
;
4305 if (!(Count
> 0 && pRects
)) {
4306 if(This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
]) {
4307 IntersectRect(&vp_rect
, &vp_rect
, &This
->stateBlock
->scissorRect
);
4309 if (context
->render_offscreen
)
4311 glScissor(vp_rect
.left
, vp_rect
.top
,
4312 vp_rect
.right
- vp_rect
.left
, vp_rect
.bottom
- vp_rect
.top
);
4314 glScissor(vp_rect
.left
, drawable_height
- vp_rect
.bottom
,
4315 vp_rect
.right
- vp_rect
.left
, vp_rect
.bottom
- vp_rect
.top
);
4317 checkGLcall("glScissor");
4319 checkGLcall("glClear");
4321 /* Now process each rect in turn */
4322 for (i
= 0; i
< Count
; i
++) {
4323 /* Note gl uses lower left, width/height */
4324 IntersectRect((RECT
*)&curRect
, &vp_rect
, (const RECT
*)&pRects
[i
]);
4325 if(This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
]) {
4326 IntersectRect((RECT
*) &curRect
, (RECT
*) &curRect
, &This
->stateBlock
->scissorRect
);
4328 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This
,
4329 pRects
[i
].x1
, pRects
[i
].y1
, pRects
[i
].x2
, pRects
[i
].y2
,
4330 curRect
.x1
, (target
->currentDesc
.Height
- curRect
.y2
),
4331 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
4333 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4334 * The rectangle is not cleared, no error is returned, but further rectanlges are
4335 * still cleared if they are valid
4337 if(curRect
.x1
> curRect
.x2
|| curRect
.y1
> curRect
.y2
) {
4338 TRACE("Rectangle with negative dimensions, ignoring\n");
4342 if (context
->render_offscreen
)
4344 glScissor(curRect
.x1
, curRect
.y1
,
4345 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
4347 glScissor(curRect
.x1
, drawable_height
- curRect
.y2
,
4348 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
4350 checkGLcall("glScissor");
4353 checkGLcall("glClear");
4357 /* Restore the old values (why..?) */
4358 if (Flags
& WINED3DCLEAR_STENCIL
) {
4359 glStencilMask(This
->stateBlock
->renderState
[WINED3DRS_STENCILWRITEMASK
]);
4361 if (Flags
& WINED3DCLEAR_TARGET
) {
4362 DWORD mask
= This
->stateBlock
->renderState
[WINED3DRS_COLORWRITEENABLE
];
4363 glColorMask(mask
& WINED3DCOLORWRITEENABLE_RED
? GL_TRUE
: GL_FALSE
,
4364 mask
& WINED3DCOLORWRITEENABLE_GREEN
? GL_TRUE
: GL_FALSE
,
4365 mask
& WINED3DCOLORWRITEENABLE_BLUE
? GL_TRUE
: GL_FALSE
,
4366 mask
& WINED3DCOLORWRITEENABLE_ALPHA
? GL_TRUE
: GL_FALSE
);
4368 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4369 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4371 IWineD3DSurface_ModifyLocation((IWineD3DSurface
*)target
, SFLAG_INDRAWABLE
, TRUE
);
4373 if (Flags
& WINED3DCLEAR_ZBUFFER
) {
4374 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
4375 DWORD location
= context
->render_offscreen
? SFLAG_DS_OFFSCREEN
: SFLAG_DS_ONSCREEN
;
4376 surface_modify_ds_location(This
->stencilBufferTarget
, location
);
4381 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface
*)target
, &IID_IWineD3DSwapChain
, (void **)&swapchain
))) {
4382 if (target
== (IWineD3DSurfaceImpl
*) swapchain
->frontBuffer
) {
4385 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
4388 context_release(context
);
4393 static HRESULT WINAPI
IWineD3DDeviceImpl_Clear(IWineD3DDevice
*iface
, DWORD Count
, CONST WINED3DRECT
* pRects
,
4394 DWORD Flags
, WINED3DCOLOR Color
, float Z
, DWORD Stencil
) {
4395 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4396 IWineD3DSurfaceImpl
*target
= (IWineD3DSurfaceImpl
*)This
->render_targets
[0];
4398 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This
,
4399 Count
, pRects
, Flags
, Color
, Z
, Stencil
);
4401 if(Flags
& (WINED3DCLEAR_ZBUFFER
| WINED3DCLEAR_STENCIL
) && This
->stencilBufferTarget
== NULL
) {
4402 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4403 /* TODO: What about depth stencil buffers without stencil bits? */
4404 return WINED3DERR_INVALIDCALL
;
4407 return IWineD3DDeviceImpl_ClearSurface(This
, target
, Count
, pRects
, Flags
, Color
, Z
, Stencil
);
4414 static void WINAPI
IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice
*iface
,
4415 WINED3DPRIMITIVETYPE primitive_type
)
4417 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4419 TRACE("iface %p, primitive_type %s\n", iface
, debug_d3dprimitivetype(primitive_type
));
4421 This
->updateStateBlock
->changed
.primitive_type
= TRUE
;
4422 This
->updateStateBlock
->gl_primitive_type
= gl_primitive_type_from_d3d(primitive_type
);
4425 static void WINAPI
IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice
*iface
,
4426 WINED3DPRIMITIVETYPE
*primitive_type
)
4428 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4430 TRACE("iface %p, primitive_type %p\n", iface
, primitive_type
);
4432 *primitive_type
= d3d_primitive_type_from_gl(This
->stateBlock
->gl_primitive_type
);
4434 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type
));
4437 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice
*iface
, UINT StartVertex
, UINT vertex_count
)
4439 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4441 TRACE("(%p) : start %u, count %u\n", This
, StartVertex
, vertex_count
);
4443 if(!This
->stateBlock
->vertexDecl
) {
4444 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
4445 return WINED3DERR_INVALIDCALL
;
4448 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4449 if(This
->stateBlock
->streamIsUP
) {
4450 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
4451 This
->stateBlock
->streamIsUP
= FALSE
;
4454 if(This
->stateBlock
->loadBaseVertexIndex
!= 0) {
4455 This
->stateBlock
->loadBaseVertexIndex
= 0;
4456 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
4458 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4459 drawPrimitive(iface
, vertex_count
, StartVertex
/* start_idx */, 0 /* indxSize */, NULL
/* indxData */);
4463 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice
*iface
, UINT startIndex
, UINT index_count
)
4465 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4467 IWineD3DBuffer
*pIB
;
4470 pIB
= This
->stateBlock
->pIndexData
;
4472 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4473 * without an index buffer set. (The first time at least...)
4474 * D3D8 simply dies, but I doubt it can do much harm to return
4475 * D3DERR_INVALIDCALL there as well. */
4476 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This
);
4477 return WINED3DERR_INVALIDCALL
;
4480 if(!This
->stateBlock
->vertexDecl
) {
4481 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
4482 return WINED3DERR_INVALIDCALL
;
4485 if(This
->stateBlock
->streamIsUP
) {
4486 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
4487 This
->stateBlock
->streamIsUP
= FALSE
;
4489 vbo
= ((struct wined3d_buffer
*) pIB
)->buffer_object
;
4491 TRACE("(%p) : startIndex %u, index count %u.\n", This
, startIndex
, index_count
);
4493 if (This
->stateBlock
->IndexFmt
== WINED3DFMT_R16_UINT
) {
4499 if(This
->stateBlock
->loadBaseVertexIndex
!= This
->stateBlock
->baseVertexIndex
) {
4500 This
->stateBlock
->loadBaseVertexIndex
= This
->stateBlock
->baseVertexIndex
;
4501 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
4504 drawPrimitive(iface
, index_count
, startIndex
, idxStride
,
4505 vbo
? NULL
: ((struct wined3d_buffer
*)pIB
)->resource
.allocatedMemory
);
4510 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice
*iface
, UINT vertex_count
,
4511 const void *pVertexStreamZeroData
, UINT VertexStreamZeroStride
)
4513 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4516 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4517 This
, vertex_count
, pVertexStreamZeroData
, VertexStreamZeroStride
);
4519 if(!This
->stateBlock
->vertexDecl
) {
4520 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
4521 return WINED3DERR_INVALIDCALL
;
4524 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4525 vb
= This
->stateBlock
->streamSource
[0];
4526 This
->stateBlock
->streamSource
[0] = (IWineD3DBuffer
*)pVertexStreamZeroData
;
4527 if (vb
) IWineD3DBuffer_Release(vb
);
4528 This
->stateBlock
->streamOffset
[0] = 0;
4529 This
->stateBlock
->streamStride
[0] = VertexStreamZeroStride
;
4530 This
->stateBlock
->streamIsUP
= TRUE
;
4531 This
->stateBlock
->loadBaseVertexIndex
= 0;
4533 /* TODO: Only mark dirty if drawing from a different UP address */
4534 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
4536 drawPrimitive(iface
, vertex_count
, 0 /* start_idx */, 0 /* indxSize*/, NULL
/* indxData */);
4538 /* MSDN specifies stream zero settings must be set to NULL */
4539 This
->stateBlock
->streamStride
[0] = 0;
4540 This
->stateBlock
->streamSource
[0] = NULL
;
4542 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4543 * the new stream sources or use UP drawing again
4548 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice
*iface
,
4549 UINT index_count
, const void *pIndexData
, WINED3DFORMAT IndexDataFormat
,
4550 const void *pVertexStreamZeroData
, UINT VertexStreamZeroStride
)
4553 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4557 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4558 This
, index_count
, pIndexData
, IndexDataFormat
, pVertexStreamZeroData
, VertexStreamZeroStride
);
4560 if(!This
->stateBlock
->vertexDecl
) {
4561 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
4562 return WINED3DERR_INVALIDCALL
;
4565 if (IndexDataFormat
== WINED3DFMT_R16_UINT
) {
4571 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4572 vb
= This
->stateBlock
->streamSource
[0];
4573 This
->stateBlock
->streamSource
[0] = (IWineD3DBuffer
*)pVertexStreamZeroData
;
4574 if (vb
) IWineD3DBuffer_Release(vb
);
4575 This
->stateBlock
->streamIsUP
= TRUE
;
4576 This
->stateBlock
->streamOffset
[0] = 0;
4577 This
->stateBlock
->streamStride
[0] = VertexStreamZeroStride
;
4579 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4580 This
->stateBlock
->baseVertexIndex
= 0;
4581 This
->stateBlock
->loadBaseVertexIndex
= 0;
4582 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4583 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
4584 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
4586 drawPrimitive(iface
, index_count
, 0 /* start_idx */, idxStride
, pIndexData
);
4588 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4589 This
->stateBlock
->streamSource
[0] = NULL
;
4590 This
->stateBlock
->streamStride
[0] = 0;
4591 ib
= This
->stateBlock
->pIndexData
;
4593 IWineD3DBuffer_Release(ib
);
4594 This
->stateBlock
->pIndexData
= NULL
;
4596 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4597 * SetStreamSource to specify a vertex buffer
4603 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice
*iface
,
4604 UINT vertex_count
, const WineDirect3DVertexStridedData
*DrawPrimStrideData
)
4606 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
4608 /* Mark the state dirty until we have nicer tracking
4609 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4612 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
4613 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
4614 This
->stateBlock
->baseVertexIndex
= 0;
4615 This
->up_strided
= DrawPrimStrideData
;
4616 drawPrimitive(iface
, vertex_count
, 0, 0, NULL
);
4617 This
->up_strided
= NULL
;
4621 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice
*iface
,
4622 UINT vertex_count
, const WineDirect3DVertexStridedData
*DrawPrimStrideData
,
4623 UINT NumVertices
, const void *pIndexData
, WINED3DFORMAT IndexDataFormat
)
4625 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
4626 DWORD idxSize
= (IndexDataFormat
== WINED3DFMT_R32_UINT
? 4 : 2);
4628 /* Mark the state dirty until we have nicer tracking
4629 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4632 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
4633 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
4634 This
->stateBlock
->streamIsUP
= TRUE
;
4635 This
->stateBlock
->baseVertexIndex
= 0;
4636 This
->up_strided
= DrawPrimStrideData
;
4637 drawPrimitive(iface
, vertex_count
, 0 /* start_idx */, idxSize
, pIndexData
);
4638 This
->up_strided
= NULL
;
4642 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4643 static HRESULT
IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice
*iface
,
4644 IWineD3DVolume
*pSourceVolume
, IWineD3DVolume
*pDestinationVolume
)
4646 WINED3DLOCKED_BOX src
;
4647 WINED3DLOCKED_BOX dst
;
4650 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4651 iface
, pSourceVolume
, pDestinationVolume
);
4653 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4654 * dirtification to improve loading performance.
4656 hr
= IWineD3DVolume_LockBox(pSourceVolume
, &src
, NULL
, WINED3DLOCK_READONLY
);
4657 if(FAILED(hr
)) return hr
;
4658 hr
= IWineD3DVolume_LockBox(pDestinationVolume
, &dst
, NULL
, WINED3DLOCK_DISCARD
);
4660 IWineD3DVolume_UnlockBox(pSourceVolume
);
4664 memcpy(dst
.pBits
, src
.pBits
, ((IWineD3DVolumeImpl
*) pDestinationVolume
)->resource
.size
);
4666 hr
= IWineD3DVolume_UnlockBox(pDestinationVolume
);
4668 IWineD3DVolume_UnlockBox(pSourceVolume
);
4670 hr
= IWineD3DVolume_UnlockBox(pSourceVolume
);
4675 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice
*iface
,
4676 IWineD3DBaseTexture
*src_texture
, IWineD3DBaseTexture
*dst_texture
)
4678 unsigned int level_count
, i
;
4679 WINED3DRESOURCETYPE type
;
4682 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface
, src_texture
, dst_texture
);
4684 /* Verify that the source and destination textures are non-NULL. */
4685 if (!src_texture
|| !dst_texture
)
4687 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4688 return WINED3DERR_INVALIDCALL
;
4691 if (src_texture
== dst_texture
)
4693 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4694 return WINED3DERR_INVALIDCALL
;
4697 /* Verify that the source and destination textures are the same type. */
4698 type
= IWineD3DBaseTexture_GetType(src_texture
);
4699 if (IWineD3DBaseTexture_GetType(dst_texture
) != type
)
4701 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4702 return WINED3DERR_INVALIDCALL
;
4705 /* Check that both textures have the identical numbers of levels. */
4706 level_count
= IWineD3DBaseTexture_GetLevelCount(src_texture
);
4707 if (IWineD3DBaseTexture_GetLevelCount(dst_texture
) != level_count
)
4709 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4710 return WINED3DERR_INVALIDCALL
;
4713 /* Make sure that the destination texture is loaded. */
4714 ((IWineD3DBaseTextureImpl
*)dst_texture
)->baseTexture
.internal_preload(dst_texture
, SRGB_RGB
);
4716 /* Update every surface level of the texture. */
4719 case WINED3DRTYPE_TEXTURE
:
4721 IWineD3DSurface
*src_surface
;
4722 IWineD3DSurface
*dst_surface
;
4724 for (i
= 0; i
< level_count
; ++i
)
4726 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)src_texture
, i
, &src_surface
);
4727 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)dst_texture
, i
, &dst_surface
);
4728 hr
= IWineD3DDevice_UpdateSurface(iface
, src_surface
, NULL
, dst_surface
, NULL
);
4729 IWineD3DSurface_Release(dst_surface
);
4730 IWineD3DSurface_Release(src_surface
);
4733 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr
);
4740 case WINED3DRTYPE_CUBETEXTURE
:
4742 IWineD3DSurface
*src_surface
;
4743 IWineD3DSurface
*dst_surface
;
4744 WINED3DCUBEMAP_FACES face
;
4746 for (i
= 0; i
< level_count
; ++i
)
4748 /* Update each cube face. */
4749 for (face
= WINED3DCUBEMAP_FACE_POSITIVE_X
; face
<= WINED3DCUBEMAP_FACE_NEGATIVE_Z
; ++face
)
4751 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)src_texture
,
4752 face
, i
, &src_surface
);
4753 if (FAILED(hr
)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face
, i
, hr
);
4754 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)dst_texture
,
4755 face
, i
, &dst_surface
);
4756 if (FAILED(hr
)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face
, i
, hr
);
4757 hr
= IWineD3DDevice_UpdateSurface(iface
, src_surface
, NULL
, dst_surface
, NULL
);
4758 IWineD3DSurface_Release(dst_surface
);
4759 IWineD3DSurface_Release(src_surface
);
4762 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr
);
4770 case WINED3DRTYPE_VOLUMETEXTURE
:
4772 IWineD3DVolume
*src_volume
;
4773 IWineD3DVolume
*dst_volume
;
4775 for (i
= 0; i
< level_count
; ++i
)
4777 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture
*)src_texture
, i
, &src_volume
);
4778 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture
*)dst_texture
, i
, &dst_volume
);
4779 hr
= IWineD3DDeviceImpl_UpdateVolume(iface
, src_volume
, dst_volume
);
4780 IWineD3DVolume_Release(dst_volume
);
4781 IWineD3DVolume_Release(src_volume
);
4784 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr
);
4792 FIXME("Unsupported texture type %#x.\n", type
);
4793 return WINED3DERR_INVALIDCALL
;
4799 static HRESULT WINAPI
IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice
*iface
,UINT iSwapChain
, IWineD3DSurface
*pDestSurface
) {
4800 IWineD3DSwapChain
*swapChain
;
4802 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
4803 if(hr
== WINED3D_OK
) {
4804 hr
= IWineD3DSwapChain_GetFrontBufferData(swapChain
, pDestSurface
);
4805 IWineD3DSwapChain_Release(swapChain
);
4810 static HRESULT WINAPI
IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice
*iface
, DWORD
* pNumPasses
) {
4811 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4812 IWineD3DBaseTextureImpl
*texture
;
4815 TRACE("(%p) : %p\n", This
, pNumPasses
);
4817 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++) {
4818 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MINFILTER
] == WINED3DTEXF_NONE
) {
4819 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i
);
4820 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER
;
4822 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MAGFILTER
] == WINED3DTEXF_NONE
) {
4823 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i
);
4824 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER
;
4827 texture
= (IWineD3DBaseTextureImpl
*) This
->stateBlock
->textures
[i
];
4828 if (!texture
|| texture
->resource
.format_desc
->Flags
& WINED3DFMT_FLAG_FILTERING
) continue;
4830 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MAGFILTER
] != WINED3DTEXF_POINT
) {
4831 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i
);
4834 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MINFILTER
] != WINED3DTEXF_POINT
) {
4835 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i
);
4838 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MIPFILTER
] != WINED3DTEXF_NONE
&&
4839 This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MIPFILTER
] != WINED3DTEXF_POINT
/* sic! */) {
4840 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i
);
4845 /* return a sensible default */
4848 TRACE("returning D3D_OK\n");
4852 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl
*device
)
4856 for (i
= 0; i
< MAX_COMBINED_SAMPLERS
; ++i
)
4858 IWineD3DBaseTextureImpl
*texture
= (IWineD3DBaseTextureImpl
*)device
->stateBlock
->textures
[i
];
4859 if (texture
&& (texture
->resource
.format_desc
->format
== WINED3DFMT_P8_UINT
4860 || texture
->resource
.format_desc
->format
== WINED3DFMT_P8_UINT_A8_UNORM
))
4862 IWineD3DDeviceImpl_MarkStateDirty(device
, STATE_SAMPLER(i
));
4867 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, CONST PALETTEENTRY
* pEntries
) {
4868 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4871 PALETTEENTRY
**palettes
;
4873 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
4875 if (PaletteNumber
>= MAX_PALETTES
) {
4876 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This
, PaletteNumber
, MAX_PALETTES
);
4877 return WINED3DERR_INVALIDCALL
;
4880 if (PaletteNumber
>= This
->NumberOfPalettes
) {
4881 NewSize
= This
->NumberOfPalettes
;
4884 } while(PaletteNumber
>= NewSize
);
4885 palettes
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, This
->palettes
, sizeof(PALETTEENTRY
*) * NewSize
);
4887 ERR("Out of memory!\n");
4888 return E_OUTOFMEMORY
;
4890 This
->palettes
= palettes
;
4891 This
->NumberOfPalettes
= NewSize
;
4894 if (!This
->palettes
[PaletteNumber
]) {
4895 This
->palettes
[PaletteNumber
] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY
) * 256);
4896 if (!This
->palettes
[PaletteNumber
]) {
4897 ERR("Out of memory!\n");
4898 return E_OUTOFMEMORY
;
4902 for (j
= 0; j
< 256; ++j
) {
4903 This
->palettes
[PaletteNumber
][j
].peRed
= pEntries
[j
].peRed
;
4904 This
->palettes
[PaletteNumber
][j
].peGreen
= pEntries
[j
].peGreen
;
4905 This
->palettes
[PaletteNumber
][j
].peBlue
= pEntries
[j
].peBlue
;
4906 This
->palettes
[PaletteNumber
][j
].peFlags
= pEntries
[j
].peFlags
;
4908 if (PaletteNumber
== This
->currentPalette
) dirtify_p8_texture_samplers(This
);
4909 TRACE("(%p) : returning\n", This
);
4913 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, PALETTEENTRY
* pEntries
) {
4914 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4916 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
4917 if (PaletteNumber
>= This
->NumberOfPalettes
|| !This
->palettes
[PaletteNumber
]) {
4918 /* What happens in such situation isn't documented; Native seems to silently abort
4919 on such conditions. Return Invalid Call. */
4920 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This
, PaletteNumber
, This
->NumberOfPalettes
);
4921 return WINED3DERR_INVALIDCALL
;
4923 for (j
= 0; j
< 256; ++j
) {
4924 pEntries
[j
].peRed
= This
->palettes
[PaletteNumber
][j
].peRed
;
4925 pEntries
[j
].peGreen
= This
->palettes
[PaletteNumber
][j
].peGreen
;
4926 pEntries
[j
].peBlue
= This
->palettes
[PaletteNumber
][j
].peBlue
;
4927 pEntries
[j
].peFlags
= This
->palettes
[PaletteNumber
][j
].peFlags
;
4929 TRACE("(%p) : returning\n", This
);
4933 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT PaletteNumber
) {
4934 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4935 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
4936 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
4937 (tested with reference rasterizer). Return Invalid Call. */
4938 if (PaletteNumber
>= This
->NumberOfPalettes
|| !This
->palettes
[PaletteNumber
]) {
4939 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This
, PaletteNumber
, This
->NumberOfPalettes
);
4940 return WINED3DERR_INVALIDCALL
;
4942 /*TODO: stateblocks */
4943 if (This
->currentPalette
!= PaletteNumber
) {
4944 This
->currentPalette
= PaletteNumber
;
4945 dirtify_p8_texture_samplers(This
);
4947 TRACE("(%p) : returning\n", This
);
4951 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT
* PaletteNumber
) {
4952 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4953 if (PaletteNumber
== NULL
) {
4954 WARN("(%p) : returning Invalid Call\n", This
);
4955 return WINED3DERR_INVALIDCALL
;
4957 /*TODO: stateblocks */
4958 *PaletteNumber
= This
->currentPalette
;
4959 TRACE("(%p) : returning %u\n", This
, *PaletteNumber
);
4963 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice
*iface
, BOOL bSoftware
) {
4964 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4968 FIXME("(%p) : stub\n", This
);
4972 This
->softwareVertexProcessing
= bSoftware
;
4977 static BOOL WINAPI
IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice
*iface
) {
4978 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4982 FIXME("(%p) : stub\n", This
);
4985 return This
->softwareVertexProcessing
;
4988 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice
*iface
,
4989 UINT swapchain_idx
, WINED3DRASTER_STATUS
*raster_status
)
4991 IWineD3DSwapChain
*swapchain
;
4994 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
4995 iface
, swapchain_idx
, raster_status
);
4997 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, swapchain_idx
, &swapchain
);
5000 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx
, hr
);
5004 hr
= IWineD3DSwapChain_GetRasterStatus(swapchain
, raster_status
);
5005 IWineD3DSwapChain_Release(swapchain
);
5008 WARN("Failed to get raster status, hr %#x.\n", hr
);
5015 static HRESULT WINAPI
IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice
*iface
, float nSegments
)
5018 if(nSegments
!= 0.0f
) {
5021 FIXME("iface %p, nSegments %.8e stub!\n", iface
, nSegments
);
5028 static float WINAPI
IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice
*iface
)
5033 FIXME("iface %p stub!\n", iface
);
5039 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice
*iface
, IWineD3DSurface
*pSourceSurface
, CONST RECT
* pSourceRect
, IWineD3DSurface
*pDestinationSurface
, CONST POINT
* pDestPoint
) {
5040 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5041 /** TODO: remove casts to IWineD3DSurfaceImpl
5042 * NOTE: move code to surface to accomplish this
5043 ****************************************/
5044 IWineD3DSurfaceImpl
*pSrcSurface
= (IWineD3DSurfaceImpl
*)pSourceSurface
;
5045 IWineD3DSurfaceImpl
*dst_impl
= (IWineD3DSurfaceImpl
*)pDestinationSurface
;
5046 int srcWidth
, srcHeight
;
5047 unsigned int srcSurfaceWidth
, srcSurfaceHeight
, destSurfaceWidth
, destSurfaceHeight
;
5048 WINED3DFORMAT destFormat
, srcFormat
;
5050 int srcLeft
, destLeft
, destTop
;
5051 WINED3DPOOL srcPool
, destPool
;
5053 int rowoffset
= 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5054 const struct GlPixelFormatDesc
*src_format_desc
, *dst_format_desc
;
5058 CONVERT_TYPES convert
= NO_CONVERSION
;
5059 struct wined3d_context
*context
;
5061 WINED3DSURFACE_DESC winedesc
;
5063 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This
, pSourceSurface
, pSourceRect
, pDestinationSurface
, pDestPoint
);
5065 IWineD3DSurface_GetDesc(pSourceSurface
, &winedesc
);
5066 srcSurfaceWidth
= winedesc
.width
;
5067 srcSurfaceHeight
= winedesc
.height
;
5068 srcPool
= winedesc
.pool
;
5069 srcFormat
= winedesc
.format
;
5071 IWineD3DSurface_GetDesc(pDestinationSurface
, &winedesc
);
5072 destSurfaceWidth
= winedesc
.width
;
5073 destSurfaceHeight
= winedesc
.height
;
5074 destPool
= winedesc
.pool
;
5075 destFormat
= winedesc
.format
;
5076 destSize
= winedesc
.size
;
5078 if(srcPool
!= WINED3DPOOL_SYSTEMMEM
|| destPool
!= WINED3DPOOL_DEFAULT
){
5079 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface
, pDestinationSurface
);
5080 return WINED3DERR_INVALIDCALL
;
5083 /* This call loads the opengl surface directly, instead of copying the surface to the
5084 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5085 * copy in sysmem and use regular surface loading.
5087 d3dfmt_get_conv(dst_impl
, FALSE
, TRUE
, &dummy
, &dummy
, &dummy
, &convert
, &bpp
, FALSE
);
5088 if(convert
!= NO_CONVERSION
) {
5089 return IWineD3DSurface_BltFast(pDestinationSurface
,
5090 pDestPoint
? pDestPoint
->x
: 0,
5091 pDestPoint
? pDestPoint
->y
: 0,
5092 pSourceSurface
, pSourceRect
, 0);
5095 if (destFormat
== WINED3DFMT_UNKNOWN
) {
5096 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This
);
5097 IWineD3DSurface_SetFormat(pDestinationSurface
, srcFormat
);
5099 /* Get the update surface description */
5100 IWineD3DSurface_GetDesc(pDestinationSurface
, &winedesc
);
5103 context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
5106 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
5107 checkGLcall("glActiveTextureARB");
5110 /* Make sure the surface is loaded and up to date */
5111 surface_internal_preload(pDestinationSurface
, SRGB_RGB
);
5112 IWineD3DSurface_BindTexture(pDestinationSurface
, FALSE
);
5114 src_format_desc
= ((IWineD3DSurfaceImpl
*)pSrcSurface
)->resource
.format_desc
;
5115 dst_format_desc
= dst_impl
->resource
.format_desc
;
5117 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5118 srcWidth
= pSourceRect
? pSourceRect
->right
- pSourceRect
->left
: srcSurfaceWidth
;
5119 srcHeight
= pSourceRect
? pSourceRect
->bottom
- pSourceRect
->top
: srcSurfaceHeight
;
5120 srcLeft
= pSourceRect
? pSourceRect
->left
: 0;
5121 destLeft
= pDestPoint
? pDestPoint
->x
: 0;
5122 destTop
= pDestPoint
? pDestPoint
->y
: 0;
5125 /* This function doesn't support compressed textures
5126 the pitch is just bytesPerPixel * width */
5127 if(srcWidth
!= srcSurfaceWidth
|| srcLeft
){
5128 rowoffset
= srcSurfaceWidth
* src_format_desc
->byte_count
;
5129 offset
+= srcLeft
* src_format_desc
->byte_count
;
5130 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5132 /* TODO DXT formats */
5134 if(pSourceRect
!= NULL
&& pSourceRect
->top
!= 0){
5135 offset
+= pSourceRect
->top
* srcSurfaceWidth
* src_format_desc
->byte_count
;
5137 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5138 This
, dst_impl
->texture_level
, destLeft
, destTop
, srcWidth
, srcHeight
, dst_format_desc
->glFormat
,
5139 dst_format_desc
->glType
, IWineD3DSurface_GetData(pSourceSurface
), offset
);
5142 if (IWineD3DSurface_GetData(pSourceSurface
) == NULL
) {
5144 /* need to lock the surface to get the data */
5145 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5150 /* TODO: Cube and volume support */
5152 /* not a whole row so we have to do it a line at a time */
5155 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5156 const unsigned char* data
=((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface
)) + offset
;
5158 for (j
= destTop
; j
< (srcHeight
+ destTop
); ++j
)
5160 glTexSubImage2D(dst_impl
->texture_target
, dst_impl
->texture_level
, destLeft
, j
,
5161 srcWidth
, 1, dst_format_desc
->glFormat
, dst_format_desc
->glType
,data
);
5165 } else { /* Full width, so just write out the whole texture */
5166 const unsigned char* data
= ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface
)) + offset
;
5168 if (dst_format_desc
->Flags
& WINED3DFMT_FLAG_COMPRESSED
)
5170 if (destSurfaceHeight
!= srcHeight
|| destSurfaceWidth
!= srcWidth
)
5172 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across. */
5173 FIXME("Updating part of a compressed texture is not supported.\n");
5175 if (destFormat
!= srcFormat
)
5177 FIXME("Updating mixed format compressed textures is not supported.\n");
5181 GL_EXTCALL(glCompressedTexImage2DARB(dst_impl
->texture_target
, dst_impl
->texture_level
,
5182 dst_format_desc
->glInternal
, srcWidth
, srcHeight
, 0, destSize
, data
));
5187 glTexSubImage2D(dst_impl
->texture_target
, dst_impl
->texture_level
, destLeft
, destTop
,
5188 srcWidth
, srcHeight
, dst_format_desc
->glFormat
, dst_format_desc
->glType
, data
);
5191 checkGLcall("glTexSubImage2D");
5194 context_release(context
);
5196 IWineD3DSurface_ModifyLocation(pDestinationSurface
, SFLAG_INTEXTURE
, TRUE
);
5197 sampler
= This
->rev_tex_unit_map
[0];
5198 if (sampler
!= WINED3D_UNMAPPED_STAGE
)
5200 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(sampler
));
5206 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice
*iface
, UINT Handle
, CONST
float* pNumSegs
, CONST WINED3DRECTPATCH_INFO
* pRectPatchInfo
) {
5207 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5208 struct WineD3DRectPatch
*patch
;
5209 GLenum old_primitive_type
;
5213 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This
, Handle
, pNumSegs
, pRectPatchInfo
);
5215 if(!(Handle
|| pRectPatchInfo
)) {
5216 /* TODO: Write a test for the return value, thus the FIXME */
5217 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5218 return WINED3DERR_INVALIDCALL
;
5222 i
= PATCHMAP_HASHFUNC(Handle
);
5224 LIST_FOR_EACH(e
, &This
->patches
[i
]) {
5225 patch
= LIST_ENTRY(e
, struct WineD3DRectPatch
, entry
);
5226 if(patch
->Handle
== Handle
) {
5233 TRACE("Patch does not exist. Creating a new one\n");
5234 patch
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*patch
));
5235 patch
->Handle
= Handle
;
5236 list_add_head(&This
->patches
[i
], &patch
->entry
);
5238 TRACE("Found existing patch %p\n", patch
);
5241 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5242 * attributes we have to tesselate, read back, and draw. This needs a patch
5243 * management structure instance. Create one.
5245 * A possible improvement is to check if a vertex shader is used, and if not directly
5248 FIXME("Drawing an uncached patch. This is slow\n");
5249 patch
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*patch
));
5252 if(pNumSegs
[0] != patch
->numSegs
[0] || pNumSegs
[1] != patch
->numSegs
[1] ||
5253 pNumSegs
[2] != patch
->numSegs
[2] || pNumSegs
[3] != patch
->numSegs
[3] ||
5254 (pRectPatchInfo
&& memcmp(pRectPatchInfo
, &patch
->RectPatchInfo
, sizeof(*pRectPatchInfo
)) != 0) ) {
5256 TRACE("Tesselation density or patch info changed, retesselating\n");
5258 if(pRectPatchInfo
) {
5259 patch
->RectPatchInfo
= *pRectPatchInfo
;
5261 patch
->numSegs
[0] = pNumSegs
[0];
5262 patch
->numSegs
[1] = pNumSegs
[1];
5263 patch
->numSegs
[2] = pNumSegs
[2];
5264 patch
->numSegs
[3] = pNumSegs
[3];
5266 hr
= tesselate_rectpatch(This
, patch
);
5268 WARN("Patch tesselation failed\n");
5270 /* Do not release the handle to store the params of the patch */
5272 HeapFree(GetProcessHeap(), 0, patch
);
5278 This
->currentPatch
= patch
;
5279 old_primitive_type
= This
->stateBlock
->gl_primitive_type
;
5280 This
->stateBlock
->gl_primitive_type
= GL_TRIANGLES
;
5281 IWineD3DDevice_DrawPrimitiveStrided(iface
, patch
->numSegs
[0] * patch
->numSegs
[1] * 2 * 3, &patch
->strided
);
5282 This
->stateBlock
->gl_primitive_type
= old_primitive_type
;
5283 This
->currentPatch
= NULL
;
5285 /* Destroy uncached patches */
5287 HeapFree(GetProcessHeap(), 0, patch
->mem
);
5288 HeapFree(GetProcessHeap(), 0, patch
);
5293 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice
*iface
,
5294 UINT handle
, const float *segment_count
, const WINED3DTRIPATCH_INFO
*patch_info
)
5296 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5297 iface
, handle
, segment_count
, patch_info
);
5302 static HRESULT WINAPI
IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice
*iface
, UINT Handle
) {
5303 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5305 struct WineD3DRectPatch
*patch
;
5307 TRACE("(%p) Handle(%d)\n", This
, Handle
);
5309 i
= PATCHMAP_HASHFUNC(Handle
);
5310 LIST_FOR_EACH(e
, &This
->patches
[i
]) {
5311 patch
= LIST_ENTRY(e
, struct WineD3DRectPatch
, entry
);
5312 if(patch
->Handle
== Handle
) {
5313 TRACE("Deleting patch %p\n", patch
);
5314 list_remove(&patch
->entry
);
5315 HeapFree(GetProcessHeap(), 0, patch
->mem
);
5316 HeapFree(GetProcessHeap(), 0, patch
);
5321 /* TODO: Write a test for the return value */
5322 FIXME("Attempt to destroy nonexistent patch\n");
5323 return WINED3DERR_INVALIDCALL
;
5326 static IWineD3DSwapChain
*get_swapchain(IWineD3DSurface
*target
) {
5328 IWineD3DSwapChain
*swapchain
;
5330 hr
= IWineD3DSurface_GetContainer(target
, &IID_IWineD3DSwapChain
, (void **)&swapchain
);
5331 if (SUCCEEDED(hr
)) {
5332 IWineD3DSwapChain_Release((IUnknown
*)swapchain
);
5339 static void color_fill_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*surface
,
5340 const WINED3DRECT
*rect
, const float color
[4])
5342 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5343 struct wined3d_context
*context
;
5345 if (!surface_is_offscreen(surface
))
5347 TRACE("Surface %p is onscreen\n", surface
);
5349 context
= context_acquire(This
, surface
, CTXUSAGE_RESOURCELOAD
);
5351 context_bind_fbo(context
, GL_FRAMEBUFFER
, NULL
);
5352 context_set_draw_buffer(context
, surface_get_gl_buffer(surface
));
5356 TRACE("Surface %p is offscreen\n", surface
);
5358 context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
5360 context_bind_fbo(context
, GL_FRAMEBUFFER
, &context
->dst_fbo
);
5361 context_attach_surface_fbo(context
, GL_FRAMEBUFFER
, 0, surface
);
5362 context_attach_depth_stencil_fbo(context
, GL_FRAMEBUFFER
, NULL
, FALSE
);
5366 glEnable(GL_SCISSOR_TEST
);
5367 if(surface_is_offscreen(surface
)) {
5368 glScissor(rect
->x1
, rect
->y1
, rect
->x2
- rect
->x1
, rect
->y2
- rect
->y1
);
5370 glScissor(rect
->x1
, ((IWineD3DSurfaceImpl
*)surface
)->currentDesc
.Height
- rect
->y2
,
5371 rect
->x2
- rect
->x1
, rect
->y2
- rect
->y1
);
5373 checkGLcall("glScissor");
5374 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SCISSORRECT
);
5376 glDisable(GL_SCISSOR_TEST
);
5378 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE
));
5380 glDisable(GL_BLEND
);
5381 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE
));
5383 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
5384 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE
));
5386 glClearColor(color
[0], color
[1], color
[2], color
[3]);
5387 glClear(GL_COLOR_BUFFER_BIT
);
5388 checkGLcall("glClear");
5391 context_release(context
);
5394 static inline DWORD
argb_to_fmt(DWORD color
, WINED3DFORMAT destfmt
) {
5395 unsigned int r
, g
, b
, a
;
5398 if (destfmt
== WINED3DFMT_B8G8R8A8_UNORM
5399 || destfmt
== WINED3DFMT_B8G8R8X8_UNORM
5400 || destfmt
== WINED3DFMT_B8G8R8_UNORM
)
5403 TRACE("Converting color %08x to format %s\n", color
, debug_d3dformat(destfmt
));
5405 a
= (color
& 0xff000000) >> 24;
5406 r
= (color
& 0x00ff0000) >> 16;
5407 g
= (color
& 0x0000ff00) >> 8;
5408 b
= (color
& 0x000000ff) >> 0;
5412 case WINED3DFMT_B5G6R5_UNORM
:
5413 if(r
== 0xff && g
== 0xff && b
== 0xff) return 0xffff;
5420 TRACE("Returning %08x\n", ret
);
5423 case WINED3DFMT_B5G5R5X1_UNORM
:
5424 case WINED3DFMT_B5G5R5A1_UNORM
:
5433 TRACE("Returning %08x\n", ret
);
5436 case WINED3DFMT_A8_UNORM
:
5437 TRACE("Returning %08x\n", a
);
5440 case WINED3DFMT_B4G4R4X4_UNORM
:
5441 case WINED3DFMT_B4G4R4A4_UNORM
:
5450 TRACE("Returning %08x\n", ret
);
5453 case WINED3DFMT_B2G3R3_UNORM
:
5460 TRACE("Returning %08x\n", ret
);
5463 case WINED3DFMT_R8G8B8X8_UNORM
:
5464 case WINED3DFMT_R8G8B8A8_UNORM
:
5469 TRACE("Returning %08x\n", ret
);
5472 case WINED3DFMT_B10G10R10A2_UNORM
:
5474 r
= (r
* 1024) / 256;
5475 g
= (g
* 1024) / 256;
5476 b
= (b
* 1024) / 256;
5481 TRACE("Returning %08x\n", ret
);
5484 case WINED3DFMT_R10G10B10A2_UNORM
:
5486 r
= (r
* 1024) / 256;
5487 g
= (g
* 1024) / 256;
5488 b
= (b
* 1024) / 256;
5493 TRACE("Returning %08x\n", ret
);
5497 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt
));
5502 static HRESULT WINAPI
IWineD3DDeviceImpl_ColorFill(IWineD3DDevice
*iface
,
5503 IWineD3DSurface
*pSurface
, const WINED3DRECT
*pRect
, WINED3DCOLOR color
)
5505 IWineD3DSurfaceImpl
*surface
= (IWineD3DSurfaceImpl
*) pSurface
;
5508 TRACE("iface %p, surface %p, rect %p, color 0x%08x.\n", iface
, pSurface
, pRect
, color
);
5510 if (surface
->resource
.pool
!= WINED3DPOOL_DEFAULT
&& surface
->resource
.pool
!= WINED3DPOOL_SYSTEMMEM
) {
5511 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5512 return WINED3DERR_INVALIDCALL
;
5515 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
5516 const float c
[4] = {D3DCOLOR_R(color
), D3DCOLOR_G(color
), D3DCOLOR_B(color
), D3DCOLOR_A(color
)};
5517 color_fill_fbo(iface
, pSurface
, pRect
, c
);
5520 /* Just forward this to the DirectDraw blitting engine */
5521 memset(&BltFx
, 0, sizeof(BltFx
));
5522 BltFx
.dwSize
= sizeof(BltFx
);
5523 BltFx
.u5
.dwFillColor
= argb_to_fmt(color
, surface
->resource
.format_desc
->format
);
5524 return IWineD3DSurface_Blt(pSurface
, (const RECT
*)pRect
, NULL
, NULL
,
5525 WINEDDBLT_COLORFILL
, &BltFx
, WINED3DTEXF_POINT
);
5529 static void WINAPI
IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice
*iface
,
5530 IWineD3DRendertargetView
*rendertarget_view
, const float color
[4])
5532 IWineD3DResource
*resource
;
5533 IWineD3DSurface
*surface
;
5536 hr
= IWineD3DRendertargetView_GetResource(rendertarget_view
, &resource
);
5539 ERR("Failed to get resource, hr %#x\n", hr
);
5543 if (IWineD3DResource_GetType(resource
) != WINED3DRTYPE_SURFACE
)
5545 FIXME("Only supported on surface resources\n");
5546 IWineD3DResource_Release(resource
);
5550 surface
= (IWineD3DSurface
*)resource
;
5552 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
)
5554 color_fill_fbo(iface
, surface
, NULL
, color
);
5561 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5563 c
= ((DWORD
)(color
[2] * 255.0f
));
5564 c
|= ((DWORD
)(color
[1] * 255.0f
)) << 8;
5565 c
|= ((DWORD
)(color
[0] * 255.0f
)) << 16;
5566 c
|= ((DWORD
)(color
[3] * 255.0f
)) << 24;
5568 /* Just forward this to the DirectDraw blitting engine */
5569 memset(&BltFx
, 0, sizeof(BltFx
));
5570 BltFx
.dwSize
= sizeof(BltFx
);
5571 BltFx
.u5
.dwFillColor
= argb_to_fmt(c
, ((IWineD3DSurfaceImpl
*)surface
)->resource
.format_desc
->format
);
5572 hr
= IWineD3DSurface_Blt(surface
, NULL
, NULL
, NULL
, WINEDDBLT_COLORFILL
, &BltFx
, WINED3DTEXF_POINT
);
5575 ERR("Blt failed, hr %#x\n", hr
);
5579 IWineD3DResource_Release(resource
);
5582 /* rendertarget and depth stencil functions */
5583 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice
* iface
,DWORD RenderTargetIndex
, IWineD3DSurface
**ppRenderTarget
) {
5584 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5586 if (RenderTargetIndex
>= This
->adapter
->gl_info
.limits
.buffers
)
5588 ERR("(%p) : Only %d render targets are supported.\n",
5589 This
, This
->adapter
->gl_info
.limits
.buffers
);
5590 return WINED3DERR_INVALIDCALL
;
5593 *ppRenderTarget
= This
->render_targets
[RenderTargetIndex
];
5594 TRACE("(%p) : RenderTarget %d Index returning %p\n", This
, RenderTargetIndex
, *ppRenderTarget
);
5595 /* Note inc ref on returned surface */
5596 if(*ppRenderTarget
!= NULL
)
5597 IWineD3DSurface_AddRef(*ppRenderTarget
);
5601 static HRESULT WINAPI
IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice
*iface
,
5602 IWineD3DSurface
*Front
, IWineD3DSurface
*Back
)
5604 IWineD3DSurfaceImpl
*FrontImpl
= (IWineD3DSurfaceImpl
*) Front
;
5605 IWineD3DSurfaceImpl
*BackImpl
= (IWineD3DSurfaceImpl
*) Back
;
5606 IWineD3DSwapChainImpl
*Swapchain
;
5609 TRACE("iface %p, front %p, back %p.\n", iface
, Front
, Back
);
5611 hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**) &Swapchain
);
5612 if(hr
!= WINED3D_OK
) {
5613 ERR("Can't get the swapchain\n");
5617 /* Make sure to release the swapchain */
5618 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) Swapchain
);
5620 if(FrontImpl
&& !(FrontImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) ) {
5621 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5622 return WINED3DERR_INVALIDCALL
;
5624 else if(BackImpl
&& !(BackImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)) {
5625 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5626 return WINED3DERR_INVALIDCALL
;
5629 if(Swapchain
->frontBuffer
!= Front
) {
5630 TRACE("Changing the front buffer from %p to %p\n", Swapchain
->frontBuffer
, Front
);
5632 if(Swapchain
->frontBuffer
)
5634 IWineD3DSurface_SetContainer(Swapchain
->frontBuffer
, NULL
);
5635 ((IWineD3DSurfaceImpl
*)Swapchain
->frontBuffer
)->Flags
&= ~SFLAG_SWAPCHAIN
;
5637 Swapchain
->frontBuffer
= Front
;
5639 if(Swapchain
->frontBuffer
) {
5640 IWineD3DSurface_SetContainer(Swapchain
->frontBuffer
, (IWineD3DBase
*) Swapchain
);
5641 ((IWineD3DSurfaceImpl
*)Swapchain
->frontBuffer
)->Flags
|= SFLAG_SWAPCHAIN
;
5645 if(Back
&& !Swapchain
->backBuffer
) {
5646 /* We need memory for the back buffer array - only one back buffer this way */
5647 Swapchain
->backBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DSurface
*));
5648 if(!Swapchain
->backBuffer
) {
5649 ERR("Out of memory\n");
5650 return E_OUTOFMEMORY
;
5654 if(Swapchain
->backBuffer
[0] != Back
) {
5655 TRACE("Changing the back buffer from %p to %p\n", Swapchain
->backBuffer
, Back
);
5657 /* What to do about the context here in the case of multithreading? Not sure.
5658 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5660 WARN("No active context?\n");
5663 if(!Swapchain
->backBuffer
[0]) {
5664 /* GL was told to draw to the front buffer at creation,
5667 glDrawBuffer(GL_BACK
);
5668 checkGLcall("glDrawBuffer(GL_BACK)");
5669 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5670 Swapchain
->presentParms
.BackBufferCount
= 1;
5672 /* That makes problems - disable for now */
5673 /* glDrawBuffer(GL_FRONT); */
5674 checkGLcall("glDrawBuffer(GL_FRONT)");
5675 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5676 Swapchain
->presentParms
.BackBufferCount
= 0;
5680 if(Swapchain
->backBuffer
[0])
5682 IWineD3DSurface_SetContainer(Swapchain
->backBuffer
[0], NULL
);
5683 ((IWineD3DSurfaceImpl
*)Swapchain
->backBuffer
[0])->Flags
&= ~SFLAG_SWAPCHAIN
;
5685 Swapchain
->backBuffer
[0] = Back
;
5687 if(Swapchain
->backBuffer
[0]) {
5688 IWineD3DSurface_SetContainer(Swapchain
->backBuffer
[0], (IWineD3DBase
*) Swapchain
);
5689 ((IWineD3DSurfaceImpl
*)Swapchain
->backBuffer
[0])->Flags
|= SFLAG_SWAPCHAIN
;
5691 HeapFree(GetProcessHeap(), 0, Swapchain
->backBuffer
);
5692 Swapchain
->backBuffer
= NULL
;
5700 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice
* iface
, IWineD3DSurface
**ppZStencilSurface
) {
5701 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5703 DWORD size
= sizeof(buffer
);
5705 *ppZStencilSurface
= This
->stencilBufferTarget
;
5706 /* @@ Wine registry key: HKCU\Software\Wine\Direct3D\MystIVStartupHack */
5707 if (!RegOpenKeyA( HKEY_CURRENT_USER
, "Software\\Wine\\Direct3D", &hkey
)) {
5708 if (!RegQueryValueExA( hkey
, "MystIVStartupHack", 0, NULL
, buffer
, &size
)) {
5709 if ( IS_OPTION_TRUE( buffer
[0] ) ) {
5710 TRACE("Enabling MystIVStartupHack hack\n");
5711 *ppZStencilSurface
= This
->auto_depth_stencil_buffer
;
5715 TRACE("(%p) : zStencilSurface returning %p\n", This
, *ppZStencilSurface
);
5717 if(*ppZStencilSurface
!= NULL
) {
5718 /* Note inc ref on returned surface */
5719 IWineD3DSurface_AddRef(*ppZStencilSurface
);
5722 return WINED3DERR_NOTFOUND
;
5726 void stretch_rect_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*src_surface
, WINED3DRECT
*src_rect
,
5727 IWineD3DSurface
*dst_surface
, WINED3DRECT
*dst_rect
, const WINED3DTEXTUREFILTERTYPE filter
, BOOL flip
)
5729 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5730 GLbitfield mask
= GL_COLOR_BUFFER_BIT
; /* TODO: Support blitting depth/stencil surfaces */
5731 IWineD3DSwapChain
*src_swapchain
, *dst_swapchain
;
5732 const struct wined3d_gl_info
*gl_info
;
5733 struct wined3d_context
*context
;
5735 POINT offset
= {0, 0};
5737 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5738 This
, src_surface
, src_rect
, dst_surface
, dst_rect
, debug_d3dtexturefiltertype(filter
), filter
, flip
);
5739 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
);
5740 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect
->x1
, dst_rect
->y1
, dst_rect
->x2
, dst_rect
->y2
);
5743 case WINED3DTEXF_LINEAR
:
5744 gl_filter
= GL_LINEAR
;
5748 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter
), filter
);
5749 case WINED3DTEXF_NONE
:
5750 case WINED3DTEXF_POINT
:
5751 gl_filter
= GL_NEAREST
;
5755 /* Attach src surface to src fbo */
5756 src_swapchain
= get_swapchain(src_surface
);
5757 dst_swapchain
= get_swapchain(dst_surface
);
5759 if (src_swapchain
) context
= context_acquire(This
, src_surface
, CTXUSAGE_RESOURCELOAD
);
5760 else if (dst_swapchain
) context
= context_acquire(This
, dst_surface
, CTXUSAGE_RESOURCELOAD
);
5761 else context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
5763 gl_info
= context
->gl_info
;
5765 if (!surface_is_offscreen(src_surface
))
5767 GLenum buffer
= surface_get_gl_buffer(src_surface
);
5769 TRACE("Source surface %p is onscreen\n", src_surface
);
5770 /* Make sure the drawable is up to date. In the offscreen case
5771 * attach_surface_fbo() implicitly takes care of this. */
5772 IWineD3DSurface_LoadLocation(src_surface
, SFLAG_INDRAWABLE
, NULL
);
5774 if(buffer
== GL_FRONT
) {
5777 ClientToScreen(((IWineD3DSwapChainImpl
*)src_swapchain
)->win_handle
, &offset
);
5778 GetClientRect(((IWineD3DSwapChainImpl
*)src_swapchain
)->win_handle
, &windowsize
);
5779 h
= windowsize
.bottom
- windowsize
.top
;
5780 src_rect
->x1
-= offset
.x
; src_rect
->x2
-=offset
.x
;
5781 src_rect
->y1
= offset
.y
+ h
- src_rect
->y1
;
5782 src_rect
->y2
= offset
.y
+ h
- src_rect
->y2
;
5784 src_rect
->y1
= ((IWineD3DSurfaceImpl
*)src_surface
)->currentDesc
.Height
- src_rect
->y1
;
5785 src_rect
->y2
= ((IWineD3DSurfaceImpl
*)src_surface
)->currentDesc
.Height
- src_rect
->y2
;
5789 context_bind_fbo(context
, GL_READ_FRAMEBUFFER
, NULL
);
5790 glReadBuffer(buffer
);
5791 checkGLcall("glReadBuffer()");
5793 TRACE("Source surface %p is offscreen\n", src_surface
);
5795 context_bind_fbo(context
, GL_READ_FRAMEBUFFER
, &context
->src_fbo
);
5796 context_attach_surface_fbo(context
, GL_READ_FRAMEBUFFER
, 0, src_surface
);
5797 glReadBuffer(GL_COLOR_ATTACHMENT0
);
5798 checkGLcall("glReadBuffer()");
5799 context_attach_depth_stencil_fbo(context
, GL_READ_FRAMEBUFFER
, NULL
, FALSE
);
5803 /* Attach dst surface to dst fbo */
5804 if (!surface_is_offscreen(dst_surface
))
5806 GLenum buffer
= surface_get_gl_buffer(dst_surface
);
5808 TRACE("Destination surface %p is onscreen\n", dst_surface
);
5809 /* Make sure the drawable is up to date. In the offscreen case
5810 * attach_surface_fbo() implicitly takes care of this. */
5811 IWineD3DSurface_LoadLocation(dst_surface
, SFLAG_INDRAWABLE
, NULL
);
5813 if(buffer
== GL_FRONT
) {
5816 ClientToScreen(((IWineD3DSwapChainImpl
*)dst_swapchain
)->win_handle
, &offset
);
5817 GetClientRect(((IWineD3DSwapChainImpl
*)dst_swapchain
)->win_handle
, &windowsize
);
5818 h
= windowsize
.bottom
- windowsize
.top
;
5819 dst_rect
->x1
-= offset
.x
; dst_rect
->x2
-=offset
.x
;
5820 dst_rect
->y1
= offset
.y
+ h
- dst_rect
->y1
;
5821 dst_rect
->y2
= offset
.y
+ h
- dst_rect
->y2
;
5823 /* Screen coords = window coords, surface height = window height */
5824 dst_rect
->y1
= ((IWineD3DSurfaceImpl
*)dst_surface
)->currentDesc
.Height
- dst_rect
->y1
;
5825 dst_rect
->y2
= ((IWineD3DSurfaceImpl
*)dst_surface
)->currentDesc
.Height
- dst_rect
->y2
;
5829 context_bind_fbo(context
, GL_DRAW_FRAMEBUFFER
, NULL
);
5830 context_set_draw_buffer(context
, buffer
);
5834 TRACE("Destination surface %p is offscreen\n", dst_surface
);
5837 context_bind_fbo(context
, GL_DRAW_FRAMEBUFFER
, &context
->dst_fbo
);
5838 context_attach_surface_fbo(context
, GL_DRAW_FRAMEBUFFER
, 0, dst_surface
);
5839 context_set_draw_buffer(context
, GL_COLOR_ATTACHMENT0
);
5840 context_attach_depth_stencil_fbo(context
, GL_DRAW_FRAMEBUFFER
, NULL
, FALSE
);
5842 glDisable(GL_SCISSOR_TEST
);
5843 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE
));
5846 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
,
5847 dst_rect
->x1
, dst_rect
->y2
, dst_rect
->x2
, dst_rect
->y1
, mask
, gl_filter
);
5848 checkGLcall("glBlitFramebuffer()");
5850 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
,
5851 dst_rect
->x1
, dst_rect
->y1
, dst_rect
->x2
, dst_rect
->y2
, mask
, gl_filter
);
5852 checkGLcall("glBlitFramebuffer()");
5856 context_release(context
);
5858 IWineD3DSurface_ModifyLocation(dst_surface
, SFLAG_INDRAWABLE
, TRUE
);
5861 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice
*iface
, DWORD RenderTargetIndex
, IWineD3DSurface
*pRenderTarget
,
5862 BOOL set_viewport
) {
5863 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5865 TRACE("(%p) : Setting rendertarget %d to %p\n", This
, RenderTargetIndex
, pRenderTarget
);
5867 if (RenderTargetIndex
>= This
->adapter
->gl_info
.limits
.buffers
)
5869 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
5870 This
, RenderTargetIndex
, This
->adapter
->gl_info
.limits
.buffers
);
5871 return WINED3DERR_INVALIDCALL
;
5874 /* MSDN says that null disables the render target
5875 but a device must always be associated with a render target
5876 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5878 if (RenderTargetIndex
== 0 && pRenderTarget
== NULL
) {
5879 FIXME("Trying to set render target 0 to NULL\n");
5880 return WINED3DERR_INVALIDCALL
;
5882 if (pRenderTarget
&& !(((IWineD3DSurfaceImpl
*)pRenderTarget
)->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)) {
5883 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
);
5884 return WINED3DERR_INVALIDCALL
;
5887 /* If we are trying to set what we already have, don't bother */
5888 if (pRenderTarget
== This
->render_targets
[RenderTargetIndex
]) {
5889 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5892 if(pRenderTarget
) IWineD3DSurface_AddRef(pRenderTarget
);
5893 if(This
->render_targets
[RenderTargetIndex
]) IWineD3DSurface_Release(This
->render_targets
[RenderTargetIndex
]);
5894 This
->render_targets
[RenderTargetIndex
] = pRenderTarget
;
5896 /* Render target 0 is special */
5897 if(RenderTargetIndex
== 0 && set_viewport
) {
5898 /* Finally, reset the viewport and scissor rect as the MSDN states.
5899 * Tests show that stateblock recording is ignored, the change goes
5900 * directly into the primary stateblock.
5902 This
->stateBlock
->viewport
.Height
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Height
;
5903 This
->stateBlock
->viewport
.Width
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Width
;
5904 This
->stateBlock
->viewport
.X
= 0;
5905 This
->stateBlock
->viewport
.Y
= 0;
5906 This
->stateBlock
->viewport
.MaxZ
= 1.0f
;
5907 This
->stateBlock
->viewport
.MinZ
= 0.0f
;
5908 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VIEWPORT
);
5910 This
->stateBlock
->scissorRect
.top
= 0;
5911 This
->stateBlock
->scissorRect
.left
= 0;
5912 This
->stateBlock
->scissorRect
.right
= This
->stateBlock
->viewport
.Width
;
5913 This
->stateBlock
->scissorRect
.bottom
= This
->stateBlock
->viewport
.Height
;
5914 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SCISSORRECT
);
5919 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice
*iface
, IWineD3DSurface
*pNewZStencil
) {
5920 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5921 HRESULT hr
= WINED3D_OK
;
5922 IWineD3DSurface
*tmp
;
5924 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This
, This
->stencilBufferTarget
, pNewZStencil
);
5926 if (pNewZStencil
== This
->stencilBufferTarget
) {
5927 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5929 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
5930 * depending on the renter target implementation being used.
5931 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5932 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5933 * stencil buffer and incur an extra memory overhead
5934 ******************************************************/
5936 if (This
->stencilBufferTarget
) {
5937 if (((IWineD3DSwapChainImpl
*)This
->swapchains
[0])->presentParms
.Flags
& WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5938 || ((IWineD3DSurfaceImpl
*)This
->stencilBufferTarget
)->Flags
& SFLAG_DISCARD
) {
5939 surface_modify_ds_location(This
->stencilBufferTarget
, SFLAG_DS_DISCARDED
);
5941 struct wined3d_context
*context
= context_acquire(This
, This
->render_targets
[0], CTXUSAGE_RESOURCELOAD
);
5942 surface_load_ds_location(This
->stencilBufferTarget
, context
, SFLAG_DS_OFFSCREEN
);
5943 surface_modify_ds_location(This
->stencilBufferTarget
, SFLAG_DS_OFFSCREEN
);
5944 context_release(context
);
5948 tmp
= This
->stencilBufferTarget
;
5949 This
->stencilBufferTarget
= pNewZStencil
;
5950 /* should we be calling the parent or the wined3d surface? */
5951 if (NULL
!= This
->stencilBufferTarget
) IWineD3DSurface_AddRef(This
->stencilBufferTarget
);
5952 if (NULL
!= tmp
) IWineD3DSurface_Release(tmp
);
5955 if((!tmp
&& pNewZStencil
) || (!pNewZStencil
&& tmp
)) {
5956 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5957 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ZENABLE
));
5958 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_STENCILENABLE
));
5959 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_STENCILWRITEMASK
));
5966 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice
* iface
, UINT XHotSpot
,
5967 UINT YHotSpot
, IWineD3DSurface
*pCursorBitmap
) {
5968 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5969 /* TODO: the use of Impl is deprecated. */
5970 IWineD3DSurfaceImpl
* pSur
= (IWineD3DSurfaceImpl
*) pCursorBitmap
;
5971 WINED3DLOCKED_RECT lockedRect
;
5973 TRACE("(%p) : Spot Pos(%u,%u)\n", This
, XHotSpot
, YHotSpot
);
5975 /* some basic validation checks */
5976 if(This
->cursorTexture
) {
5977 struct wined3d_context
*context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
5979 glDeleteTextures(1, &This
->cursorTexture
);
5981 context_release(context
);
5982 This
->cursorTexture
= 0;
5985 if ( (pSur
->currentDesc
.Width
== 32) && (pSur
->currentDesc
.Height
== 32) )
5986 This
->haveHardwareCursor
= TRUE
;
5988 This
->haveHardwareCursor
= FALSE
;
5991 WINED3DLOCKED_RECT rect
;
5993 /* MSDN: Cursor must be A8R8G8B8 */
5994 if (pSur
->resource
.format_desc
->format
!= WINED3DFMT_B8G8R8A8_UNORM
)
5996 ERR("(%p) : surface(%p) has an invalid format\n", This
, pCursorBitmap
);
5997 return WINED3DERR_INVALIDCALL
;
6000 /* MSDN: Cursor must be smaller than the display mode */
6001 if(pSur
->currentDesc
.Width
> This
->ddraw_width
||
6002 pSur
->currentDesc
.Height
> This
->ddraw_height
) {
6003 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
);
6004 return WINED3DERR_INVALIDCALL
;
6007 if (!This
->haveHardwareCursor
) {
6008 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6010 /* Do not store the surface's pointer because the application may
6011 * release it after setting the cursor image. Windows doesn't
6012 * addref the set surface, so we can't do this either without
6013 * creating circular refcount dependencies. Copy out the gl texture
6016 This
->cursorWidth
= pSur
->currentDesc
.Width
;
6017 This
->cursorHeight
= pSur
->currentDesc
.Height
;
6018 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap
, &rect
, NULL
, WINED3DLOCK_READONLY
)))
6020 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
6021 const struct GlPixelFormatDesc
*glDesc
= getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM
, gl_info
);
6022 struct wined3d_context
*context
;
6023 char *mem
, *bits
= rect
.pBits
;
6024 GLint intfmt
= glDesc
->glInternal
;
6025 GLint format
= glDesc
->glFormat
;
6026 GLint type
= glDesc
->glType
;
6027 INT height
= This
->cursorHeight
;
6028 INT width
= This
->cursorWidth
;
6029 INT bpp
= glDesc
->byte_count
;
6033 /* Reformat the texture memory (pitch and width can be
6035 mem
= HeapAlloc(GetProcessHeap(), 0, width
* height
* bpp
);
6036 for(i
= 0; i
< height
; i
++)
6037 memcpy(&mem
[width
* bpp
* i
], &bits
[rect
.Pitch
* i
], width
* bpp
);
6038 IWineD3DSurface_UnlockRect(pCursorBitmap
);
6040 context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
6044 if (gl_info
->supported
[APPLE_CLIENT_STORAGE
])
6046 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
6047 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6050 /* Make sure that a proper texture unit is selected */
6051 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
6052 checkGLcall("glActiveTextureARB");
6053 sampler
= This
->rev_tex_unit_map
[0];
6054 if (sampler
!= WINED3D_UNMAPPED_STAGE
)
6056 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(sampler
));
6058 /* Create a new cursor texture */
6059 glGenTextures(1, &This
->cursorTexture
);
6060 checkGLcall("glGenTextures");
6061 glBindTexture(GL_TEXTURE_2D
, This
->cursorTexture
);
6062 checkGLcall("glBindTexture");
6063 /* Copy the bitmap memory into the cursor texture */
6064 glTexImage2D(GL_TEXTURE_2D
, 0, intfmt
, width
, height
, 0, format
, type
, mem
);
6065 HeapFree(GetProcessHeap(), 0, mem
);
6066 checkGLcall("glTexImage2D");
6068 if (gl_info
->supported
[APPLE_CLIENT_STORAGE
])
6070 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
6071 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6076 context_release(context
);
6080 FIXME("A cursor texture was not returned.\n");
6081 This
->cursorTexture
= 0;
6086 /* Draw a hardware cursor */
6087 ICONINFO cursorInfo
;
6089 /* Create and clear maskBits because it is not needed for
6090 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6092 DWORD
*maskBits
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
6093 (pSur
->currentDesc
.Width
* pSur
->currentDesc
.Height
/ 8));
6094 IWineD3DSurface_LockRect(pCursorBitmap
, &lockedRect
, NULL
,
6095 WINED3DLOCK_NO_DIRTY_UPDATE
|
6096 WINED3DLOCK_READONLY
6098 TRACE("width: %i height: %i\n", pSur
->currentDesc
.Width
,
6099 pSur
->currentDesc
.Height
);
6101 cursorInfo
.fIcon
= FALSE
;
6102 cursorInfo
.xHotspot
= XHotSpot
;
6103 cursorInfo
.yHotspot
= YHotSpot
;
6104 cursorInfo
.hbmMask
= CreateBitmap(pSur
->currentDesc
.Width
, pSur
->currentDesc
.Height
,
6106 cursorInfo
.hbmColor
= CreateBitmap(pSur
->currentDesc
.Width
, pSur
->currentDesc
.Height
,
6107 1, 32, lockedRect
.pBits
);
6108 IWineD3DSurface_UnlockRect(pCursorBitmap
);
6109 /* Create our cursor and clean up. */
6110 cursor
= CreateIconIndirect(&cursorInfo
);
6112 if (cursorInfo
.hbmMask
) DeleteObject(cursorInfo
.hbmMask
);
6113 if (cursorInfo
.hbmColor
) DeleteObject(cursorInfo
.hbmColor
);
6114 if (This
->hardwareCursor
) DestroyCursor(This
->hardwareCursor
);
6115 This
->hardwareCursor
= cursor
;
6116 HeapFree(GetProcessHeap(), 0, maskBits
);
6120 This
->xHotSpot
= XHotSpot
;
6121 This
->yHotSpot
= YHotSpot
;
6125 static void WINAPI
IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice
* iface
, int XScreenSpace
, int YScreenSpace
, DWORD Flags
) {
6126 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6127 TRACE("(%p) : SetPos to (%u,%u)\n", This
, XScreenSpace
, YScreenSpace
);
6129 This
->xScreenSpace
= XScreenSpace
;
6130 This
->yScreenSpace
= YScreenSpace
;
6136 static BOOL WINAPI
IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice
* iface
, BOOL bShow
) {
6137 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6138 BOOL oldVisible
= This
->bCursorVisible
;
6141 TRACE("(%p) : visible(%d)\n", This
, bShow
);
6144 * When ShowCursor is first called it should make the cursor appear at the OS's last
6145 * known cursor position. Because of this, some applications just repetitively call
6146 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6149 This
->xScreenSpace
= pt
.x
;
6150 This
->yScreenSpace
= pt
.y
;
6152 if (This
->haveHardwareCursor
) {
6153 This
->bCursorVisible
= bShow
;
6155 SetCursor(This
->hardwareCursor
);
6161 if (This
->cursorTexture
)
6162 This
->bCursorVisible
= bShow
;
6168 static HRESULT WINAPI
evict_managed_resource(IWineD3DResource
*resource
, void *data
) {
6169 TRACE("checking resource %p for eviction\n", resource
);
6170 if(((IWineD3DResourceImpl
*) resource
)->resource
.pool
== WINED3DPOOL_MANAGED
) {
6171 TRACE("Evicting %p\n", resource
);
6172 IWineD3DResource_UnLoad(resource
);
6174 IWineD3DResource_Release(resource
);
6178 static HRESULT WINAPI
IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice
*iface
)
6180 TRACE("iface %p.\n", iface
);
6182 IWineD3DDevice_EnumResources(iface
, evict_managed_resource
, NULL
);
6186 static HRESULT
updateSurfaceDesc(IWineD3DSurfaceImpl
*surface
, const WINED3DPRESENT_PARAMETERS
* pPresentationParameters
)
6188 IWineD3DDeviceImpl
*device
= surface
->resource
.device
;
6189 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
6191 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6192 if(surface
->Flags
& SFLAG_DIBSECTION
) {
6193 /* Release the DC */
6194 SelectObject(surface
->hDC
, surface
->dib
.holdbitmap
);
6195 DeleteDC(surface
->hDC
);
6196 /* Release the DIB section */
6197 DeleteObject(surface
->dib
.DIBsection
);
6198 surface
->dib
.bitmap_data
= NULL
;
6199 surface
->resource
.allocatedMemory
= NULL
;
6200 surface
->Flags
&= ~SFLAG_DIBSECTION
;
6202 surface
->currentDesc
.Width
= pPresentationParameters
->BackBufferWidth
;
6203 surface
->currentDesc
.Height
= pPresentationParameters
->BackBufferHeight
;
6204 if (gl_info
->supported
[ARB_TEXTURE_NON_POWER_OF_TWO
] || gl_info
->supported
[ARB_TEXTURE_RECTANGLE
]
6205 || gl_info
->supported
[WINE_NORMALIZED_TEXRECT
])
6207 surface
->pow2Width
= pPresentationParameters
->BackBufferWidth
;
6208 surface
->pow2Height
= pPresentationParameters
->BackBufferHeight
;
6210 surface
->pow2Width
= surface
->pow2Height
= 1;
6211 while (surface
->pow2Width
< pPresentationParameters
->BackBufferWidth
) surface
->pow2Width
<<= 1;
6212 while (surface
->pow2Height
< pPresentationParameters
->BackBufferHeight
) surface
->pow2Height
<<= 1;
6214 surface
->glRect
.left
= 0;
6215 surface
->glRect
.top
= 0;
6216 surface
->glRect
.right
= surface
->pow2Width
;
6217 surface
->glRect
.bottom
= surface
->pow2Height
;
6219 if (surface
->texture_name
)
6221 struct wined3d_context
*context
= context_acquire(device
, NULL
, CTXUSAGE_RESOURCELOAD
);
6223 glDeleteTextures(1, &surface
->texture_name
);
6225 context_release(context
);
6226 surface
->texture_name
= 0;
6227 surface
->Flags
&= ~SFLAG_CLIENT
;
6229 if(surface
->pow2Width
!= pPresentationParameters
->BackBufferWidth
||
6230 surface
->pow2Height
!= pPresentationParameters
->BackBufferHeight
) {
6231 surface
->Flags
|= SFLAG_NONPOW2
;
6233 surface
->Flags
&= ~SFLAG_NONPOW2
;
6235 HeapFree(GetProcessHeap(), 0, surface
->resource
.heapMemory
);
6236 surface
->resource
.allocatedMemory
= NULL
;
6237 surface
->resource
.heapMemory
= NULL
;
6238 surface
->resource
.size
= IWineD3DSurface_GetPitch((IWineD3DSurface
*) surface
) * surface
->pow2Width
;
6240 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6242 if(!surface_init_sysmem((IWineD3DSurface
*) surface
))
6244 return E_OUTOFMEMORY
;
6249 static HRESULT WINAPI
reset_unload_resources(IWineD3DResource
*resource
, void *data
) {
6250 TRACE("Unloading resource %p\n", resource
);
6251 IWineD3DResource_UnLoad(resource
);
6252 IWineD3DResource_Release(resource
);
6256 static BOOL
is_display_mode_supported(IWineD3DDeviceImpl
*This
, const WINED3DPRESENT_PARAMETERS
*pp
)
6259 WINED3DDISPLAYMODE m
;
6262 /* All Windowed modes are supported, as is leaving the current mode */
6263 if(pp
->Windowed
) return TRUE
;
6264 if(!pp
->BackBufferWidth
) return TRUE
;
6265 if(!pp
->BackBufferHeight
) return TRUE
;
6267 count
= IWineD3D_GetAdapterModeCount(This
->wined3d
, This
->adapter
->ordinal
, WINED3DFMT_UNKNOWN
);
6268 for(i
= 0; i
< count
; i
++) {
6269 memset(&m
, 0, sizeof(m
));
6270 hr
= IWineD3D_EnumAdapterModes(This
->wined3d
, This
->adapter
->ordinal
, WINED3DFMT_UNKNOWN
, i
, &m
);
6272 ERR("EnumAdapterModes failed\n");
6274 if(m
.Width
== pp
->BackBufferWidth
&& m
.Height
== pp
->BackBufferHeight
) {
6275 /* Mode found, it is supported */
6279 /* Mode not found -> not supported */
6283 void delete_opengl_contexts(IWineD3DDevice
*iface
, IWineD3DSwapChain
*swapchain_iface
) {
6284 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6285 IWineD3DSwapChainImpl
*swapchain
= (IWineD3DSwapChainImpl
*) swapchain_iface
;
6286 const struct wined3d_gl_info
*gl_info
;
6287 struct wined3d_context
*context
;
6288 IWineD3DBaseShaderImpl
*shader
;
6290 context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
6291 gl_info
= context
->gl_info
;
6293 IWineD3DDevice_EnumResources(iface
, reset_unload_resources
, NULL
);
6294 LIST_FOR_EACH_ENTRY(shader
, &This
->shaders
, IWineD3DBaseShaderImpl
, baseShader
.shader_list_entry
) {
6295 This
->shader_backend
->shader_destroy((IWineD3DBaseShader
*) shader
);
6299 if(This
->depth_blt_texture
) {
6300 glDeleteTextures(1, &This
->depth_blt_texture
);
6301 This
->depth_blt_texture
= 0;
6303 if (This
->depth_blt_rb
) {
6304 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &This
->depth_blt_rb
);
6305 This
->depth_blt_rb
= 0;
6306 This
->depth_blt_rb_w
= 0;
6307 This
->depth_blt_rb_h
= 0;
6311 This
->blitter
->free_private(iface
);
6312 This
->frag_pipe
->free_private(iface
);
6313 This
->shader_backend
->shader_free_private(iface
);
6314 destroy_dummy_textures(This
, gl_info
);
6316 context_release(context
);
6318 while (This
->numContexts
)
6320 context_destroy(This
, This
->contexts
[0]);
6322 HeapFree(GetProcessHeap(), 0, swapchain
->context
);
6323 swapchain
->context
= NULL
;
6324 swapchain
->num_contexts
= 0;
6327 HRESULT
create_primary_opengl_context(IWineD3DDevice
*iface
, IWineD3DSwapChain
*swapchain_iface
) {
6328 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6329 IWineD3DSwapChainImpl
*swapchain
= (IWineD3DSwapChainImpl
*) swapchain_iface
;
6330 struct wined3d_context
*context
;
6332 IWineD3DSurfaceImpl
*target
;
6334 /* Recreate the primary swapchain's context */
6335 swapchain
->context
= HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain
->context
));
6336 if (!swapchain
->context
)
6338 ERR("Failed to allocate memory for swapchain context array.\n");
6339 return E_OUTOFMEMORY
;
6342 target
= (IWineD3DSurfaceImpl
*)(swapchain
->backBuffer
? swapchain
->backBuffer
[0] : swapchain
->frontBuffer
);
6343 context
= context_create(This
, target
, swapchain
->win_handle
, FALSE
, &swapchain
->presentParms
);
6346 WARN("Failed to create context.\n");
6347 HeapFree(GetProcessHeap(), 0, swapchain
->context
);
6351 swapchain
->context
[0] = context
;
6352 swapchain
->num_contexts
= 1;
6353 create_dummy_textures(This
);
6354 context_release(context
);
6356 hr
= This
->shader_backend
->shader_alloc_private(iface
);
6359 ERR("Failed to allocate shader private data, hr %#x.\n", hr
);
6363 hr
= This
->frag_pipe
->alloc_private(iface
);
6366 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr
);
6367 This
->shader_backend
->shader_free_private(iface
);
6371 hr
= This
->blitter
->alloc_private(iface
);
6374 ERR("Failed to allocate blitter private data, hr %#x.\n", hr
);
6375 This
->frag_pipe
->free_private(iface
);
6376 This
->shader_backend
->shader_free_private(iface
);
6383 context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
6384 destroy_dummy_textures(This
, context
->gl_info
);
6385 context_release(context
);
6386 context_destroy(This
, context
);
6387 HeapFree(GetProcessHeap(), 0, swapchain
->context
);
6388 swapchain
->num_contexts
= 0;
6392 static HRESULT WINAPI
IWineD3DDeviceImpl_Reset(IWineD3DDevice
* iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
) {
6393 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6394 IWineD3DSwapChainImpl
*swapchain
;
6396 BOOL DisplayModeChanged
= FALSE
;
6397 WINED3DDISPLAYMODE mode
;
6398 TRACE("(%p)\n", This
);
6400 hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**) &swapchain
);
6402 ERR("Failed to get the first implicit swapchain\n");
6406 if(!is_display_mode_supported(This
, pPresentationParameters
)) {
6407 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6408 WARN("Requested mode: %d, %d\n", pPresentationParameters
->BackBufferWidth
,
6409 pPresentationParameters
->BackBufferHeight
);
6410 IWineD3DSwapChain_Release((IWineD3DSwapChain
*)swapchain
);
6411 return WINED3DERR_INVALIDCALL
;
6414 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6415 * on an existing gl context, so there's no real need for recreation.
6417 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6419 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6421 TRACE("New params:\n");
6422 TRACE("BackBufferWidth = %d\n", pPresentationParameters
->BackBufferWidth
);
6423 TRACE("BackBufferHeight = %d\n", pPresentationParameters
->BackBufferHeight
);
6424 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters
->BackBufferFormat
));
6425 TRACE("BackBufferCount = %d\n", pPresentationParameters
->BackBufferCount
);
6426 TRACE("MultiSampleType = %d\n", pPresentationParameters
->MultiSampleType
);
6427 TRACE("MultiSampleQuality = %d\n", pPresentationParameters
->MultiSampleQuality
);
6428 TRACE("SwapEffect = %d\n", pPresentationParameters
->SwapEffect
);
6429 TRACE("hDeviceWindow = %p\n", pPresentationParameters
->hDeviceWindow
);
6430 TRACE("Windowed = %s\n", pPresentationParameters
->Windowed
? "true" : "false");
6431 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters
->EnableAutoDepthStencil
? "true" : "false");
6432 TRACE("Flags = %08x\n", pPresentationParameters
->Flags
);
6433 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters
->FullScreen_RefreshRateInHz
);
6434 TRACE("PresentationInterval = %d\n", pPresentationParameters
->PresentationInterval
);
6436 /* No special treatment of these parameters. Just store them */
6437 swapchain
->presentParms
.SwapEffect
= pPresentationParameters
->SwapEffect
;
6438 swapchain
->presentParms
.Flags
= pPresentationParameters
->Flags
;
6439 swapchain
->presentParms
.PresentationInterval
= pPresentationParameters
->PresentationInterval
;
6440 swapchain
->presentParms
.FullScreen_RefreshRateInHz
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
6442 /* What to do about these? */
6443 if(pPresentationParameters
->BackBufferCount
!= 0 &&
6444 pPresentationParameters
->BackBufferCount
!= swapchain
->presentParms
.BackBufferCount
) {
6445 ERR("Cannot change the back buffer count yet\n");
6447 if(pPresentationParameters
->BackBufferFormat
!= WINED3DFMT_UNKNOWN
&&
6448 pPresentationParameters
->BackBufferFormat
!= swapchain
->presentParms
.BackBufferFormat
) {
6449 ERR("Cannot change the back buffer format yet\n");
6451 if(pPresentationParameters
->hDeviceWindow
!= NULL
&&
6452 pPresentationParameters
->hDeviceWindow
!= swapchain
->presentParms
.hDeviceWindow
) {
6453 ERR("Cannot change the device window yet\n");
6455 if (pPresentationParameters
->EnableAutoDepthStencil
&& !This
->auto_depth_stencil_buffer
) {
6458 TRACE("Creating the depth stencil buffer\n");
6460 hrc
= IWineD3DDeviceParent_CreateDepthStencilSurface(This
->device_parent
,
6462 pPresentationParameters
->BackBufferWidth
,
6463 pPresentationParameters
->BackBufferHeight
,
6464 pPresentationParameters
->AutoDepthStencilFormat
,
6465 pPresentationParameters
->MultiSampleType
,
6466 pPresentationParameters
->MultiSampleQuality
,
6468 &This
->auto_depth_stencil_buffer
);
6471 ERR("Failed to create the depth stencil buffer\n");
6472 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
6473 return WINED3DERR_INVALIDCALL
;
6477 /* Reset the depth stencil */
6478 if (pPresentationParameters
->EnableAutoDepthStencil
)
6479 IWineD3DDevice_SetDepthStencilSurface(iface
, This
->auto_depth_stencil_buffer
);
6481 IWineD3DDevice_SetDepthStencilSurface(iface
, NULL
);
6483 TRACE("Resetting stateblock\n");
6484 IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
);
6485 IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->stateBlock
);
6487 delete_opengl_contexts(iface
, (IWineD3DSwapChain
*) swapchain
);
6489 if(pPresentationParameters
->Windowed
) {
6490 mode
.Width
= swapchain
->orig_width
;
6491 mode
.Height
= swapchain
->orig_height
;
6492 mode
.RefreshRate
= 0;
6493 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
6495 mode
.Width
= pPresentationParameters
->BackBufferWidth
;
6496 mode
.Height
= pPresentationParameters
->BackBufferHeight
;
6497 mode
.RefreshRate
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
6498 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
6501 /* Should Width == 800 && Height == 0 set 800x600? */
6502 if(pPresentationParameters
->BackBufferWidth
!= 0 && pPresentationParameters
->BackBufferHeight
!= 0 &&
6503 (pPresentationParameters
->BackBufferWidth
!= swapchain
->presentParms
.BackBufferWidth
||
6504 pPresentationParameters
->BackBufferHeight
!= swapchain
->presentParms
.BackBufferHeight
))
6508 if(!pPresentationParameters
->Windowed
) {
6509 DisplayModeChanged
= TRUE
;
6511 swapchain
->presentParms
.BackBufferWidth
= pPresentationParameters
->BackBufferWidth
;
6512 swapchain
->presentParms
.BackBufferHeight
= pPresentationParameters
->BackBufferHeight
;
6514 hr
= updateSurfaceDesc((IWineD3DSurfaceImpl
*)swapchain
->frontBuffer
, pPresentationParameters
);
6517 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
6521 for(i
= 0; i
< swapchain
->presentParms
.BackBufferCount
; i
++) {
6522 hr
= updateSurfaceDesc((IWineD3DSurfaceImpl
*)swapchain
->backBuffer
[i
], pPresentationParameters
);
6525 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
6529 if(This
->auto_depth_stencil_buffer
) {
6530 hr
= updateSurfaceDesc((IWineD3DSurfaceImpl
*)This
->auto_depth_stencil_buffer
, pPresentationParameters
);
6533 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
6539 if((pPresentationParameters
->Windowed
&& !swapchain
->presentParms
.Windowed
) ||
6540 (swapchain
->presentParms
.Windowed
&& !pPresentationParameters
->Windowed
) ||
6541 DisplayModeChanged
) {
6543 IWineD3DDevice_SetDisplayMode(iface
, 0, &mode
);
6545 if(swapchain
->win_handle
&& !pPresentationParameters
->Windowed
) {
6546 if(swapchain
->presentParms
.Windowed
) {
6547 /* switch from windowed to fs */
6548 swapchain_setup_fullscreen_window(swapchain
, pPresentationParameters
->BackBufferWidth
,
6549 pPresentationParameters
->BackBufferHeight
);
6551 /* Fullscreen -> fullscreen mode change */
6552 MoveWindow(swapchain
->win_handle
, 0, 0,
6553 pPresentationParameters
->BackBufferWidth
, pPresentationParameters
->BackBufferHeight
,
6556 } else if(swapchain
->win_handle
&& !swapchain
->presentParms
.Windowed
) {
6557 /* Fullscreen -> windowed switch */
6558 swapchain_restore_fullscreen_window(swapchain
);
6560 swapchain
->presentParms
.Windowed
= pPresentationParameters
->Windowed
;
6561 } else if(!pPresentationParameters
->Windowed
) {
6562 DWORD style
= This
->style
, exStyle
= This
->exStyle
;
6563 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6564 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6565 * Reset to clear up their mess. Guild Wars also loses the device during that.
6569 swapchain_setup_fullscreen_window(swapchain
, pPresentationParameters
->BackBufferWidth
,
6570 pPresentationParameters
->BackBufferHeight
);
6571 This
->style
= style
;
6572 This
->exStyle
= exStyle
;
6575 /* Note: No parent needed for initial internal stateblock */
6576 hr
= IWineD3DDevice_CreateStateBlock(iface
, WINED3DSBT_INIT
, (IWineD3DStateBlock
**)&This
->stateBlock
, NULL
);
6577 if (FAILED(hr
)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr
);
6578 else TRACE("Created stateblock %p\n", This
->stateBlock
);
6579 This
->updateStateBlock
= This
->stateBlock
;
6580 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
6582 hr
= IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock
*) This
->stateBlock
);
6584 ERR("Resetting the stateblock failed with error 0x%08x\n", hr
);
6587 if(wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
)
6590 GetClientRect(swapchain
->win_handle
, &client_rect
);
6592 if(!swapchain
->presentParms
.BackBufferCount
)
6594 TRACE("Single buffered rendering\n");
6595 swapchain
->render_to_fbo
= FALSE
;
6597 else if(swapchain
->presentParms
.BackBufferWidth
!= client_rect
.right
||
6598 swapchain
->presentParms
.BackBufferHeight
!= client_rect
.bottom
)
6600 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6601 swapchain
->presentParms
.BackBufferWidth
,
6602 swapchain
->presentParms
.BackBufferHeight
,
6603 client_rect
.right
, client_rect
.bottom
);
6604 swapchain
->render_to_fbo
= TRUE
;
6608 TRACE("Rendering directly to GL_BACK\n");
6609 swapchain
->render_to_fbo
= FALSE
;
6613 hr
= create_primary_opengl_context(iface
, (IWineD3DSwapChain
*) swapchain
);
6614 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
6616 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6622 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice
*iface
, BOOL enable_dialogs
)
6624 TRACE("iface %p, enable_dialogs %#x.\n", iface
, enable_dialogs
);
6626 if (!enable_dialogs
) FIXME("Dialogs cannot be disabled yet.\n");
6632 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice
*iface
, WINED3DDEVICE_CREATION_PARAMETERS
*pParameters
) {
6633 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6634 TRACE("(%p) : pParameters %p\n", This
, pParameters
);
6636 *pParameters
= This
->createParms
;
6640 static void WINAPI
IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice
* iface
, UINT iSwapChain
, DWORD Flags
, CONST WINED3DGAMMARAMP
* pRamp
) {
6641 IWineD3DSwapChain
*swapchain
;
6643 TRACE("Relaying to swapchain\n");
6645 if (IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
) == WINED3D_OK
) {
6646 IWineD3DSwapChain_SetGammaRamp(swapchain
, Flags
, pRamp
);
6647 IWineD3DSwapChain_Release(swapchain
);
6651 static void WINAPI
IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DGAMMARAMP
* pRamp
) {
6652 IWineD3DSwapChain
*swapchain
;
6654 TRACE("Relaying to swapchain\n");
6656 if (IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
) == WINED3D_OK
) {
6657 IWineD3DSwapChain_GetGammaRamp(swapchain
, pRamp
);
6658 IWineD3DSwapChain_Release(swapchain
);
6663 /** ********************************************************
6664 * Notification functions
6665 ** ********************************************************/
6666 /** This function must be called in the release of a resource when ref == 0,
6667 * the contents of resource must still be correct,
6668 * any handles to other resource held by the caller must be closed
6669 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6670 *****************************************************/
6671 void device_resource_add(IWineD3DDeviceImpl
*This
, IWineD3DResource
*resource
)
6673 TRACE("(%p) : Adding resource %p\n", This
, resource
);
6675 list_add_head(&This
->resources
, &((IWineD3DResourceImpl
*) resource
)->resource
.resource_list_entry
);
6678 static void device_resource_remove(IWineD3DDeviceImpl
*This
, IWineD3DResource
*resource
)
6680 TRACE("(%p) : Removing resource %p\n", This
, resource
);
6682 list_remove(&((IWineD3DResourceImpl
*) resource
)->resource
.resource_list_entry
);
6685 void device_resource_released(IWineD3DDeviceImpl
*This
, IWineD3DResource
*resource
)
6687 WINED3DRESOURCETYPE type
= IWineD3DResource_GetType(resource
);
6690 TRACE("(%p) : resource %p\n", This
, resource
);
6692 context_resource_released((IWineD3DDevice
*)This
, resource
, type
);
6695 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6696 case WINED3DRTYPE_SURFACE
: {
6699 if (This
->d3d_initialized
)
6701 for (i
= 0; i
< This
->adapter
->gl_info
.limits
.buffers
; ++i
)
6703 if (This
->render_targets
[i
] == (IWineD3DSurface
*)resource
) {
6704 This
->render_targets
[i
] = NULL
;
6707 if (This
->stencilBufferTarget
== (IWineD3DSurface
*)resource
) {
6708 This
->stencilBufferTarget
= NULL
;
6714 case WINED3DRTYPE_TEXTURE
:
6715 case WINED3DRTYPE_CUBETEXTURE
:
6716 case WINED3DRTYPE_VOLUMETEXTURE
:
6717 for (counter
= 0; counter
< MAX_COMBINED_SAMPLERS
; counter
++) {
6718 if (This
->stateBlock
!= NULL
&& This
->stateBlock
->textures
[counter
] == (IWineD3DBaseTexture
*)resource
) {
6719 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter
, resource
);
6720 This
->stateBlock
->textures
[counter
] = NULL
;
6722 if (This
->updateStateBlock
!= This
->stateBlock
){
6723 if (This
->updateStateBlock
->textures
[counter
] == (IWineD3DBaseTexture
*)resource
) {
6724 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter
, resource
);
6725 This
->updateStateBlock
->textures
[counter
] = NULL
;
6730 case WINED3DRTYPE_VOLUME
:
6731 /* TODO: nothing really? */
6733 case WINED3DRTYPE_BUFFER
:
6736 TRACE("Cleaning up stream pointers\n");
6738 for(streamNumber
= 0; streamNumber
< MAX_STREAMS
; streamNumber
++){
6739 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6740 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6742 if (This
->updateStateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
6743 if ((IWineD3DResource
*)This
->updateStateBlock
->streamSource
[streamNumber
] == resource
) {
6744 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber
);
6745 This
->updateStateBlock
->streamSource
[streamNumber
] = 0;
6746 /* Set changed flag? */
6749 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) */
6750 if ((IWineD3DResource
*)This
->stateBlock
->streamSource
[streamNumber
] == resource
) {
6751 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber
);
6752 This
->stateBlock
->streamSource
[streamNumber
] = 0;
6757 if (This
->updateStateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
6758 if (This
->updateStateBlock
->pIndexData
== (IWineD3DBuffer
*)resource
) {
6759 This
->updateStateBlock
->pIndexData
= NULL
;
6762 if (This
->stateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
6763 if (This
->stateBlock
->pIndexData
== (IWineD3DBuffer
*)resource
) {
6764 This
->stateBlock
->pIndexData
= NULL
;
6771 FIXME("(%p) unknown resource type %p %u\n", This
, resource
, IWineD3DResource_GetType(resource
));
6776 /* Remove the resource from the resourceStore */
6777 device_resource_remove(This
, resource
);
6779 TRACE("Resource released\n");
6783 static HRESULT WINAPI
IWineD3DDeviceImpl_EnumResources(IWineD3DDevice
*iface
, D3DCB_ENUMRESOURCES pCallback
, void *pData
) {
6784 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6785 IWineD3DResourceImpl
*resource
, *cursor
;
6787 TRACE("(%p)->(%p,%p)\n", This
, pCallback
, pData
);
6789 LIST_FOR_EACH_ENTRY_SAFE(resource
, cursor
, &This
->resources
, IWineD3DResourceImpl
, resource
.resource_list_entry
) {
6790 TRACE("enumerating resource %p\n", resource
);
6791 IWineD3DResource_AddRef((IWineD3DResource
*) resource
);
6792 ret
= pCallback((IWineD3DResource
*) resource
, pData
);
6793 if(ret
== S_FALSE
) {
6794 TRACE("Canceling enumeration\n");
6801 /**********************************************************
6802 * IWineD3DDevice VTbl follows
6803 **********************************************************/
6805 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl
=
6807 /*** IUnknown methods ***/
6808 IWineD3DDeviceImpl_QueryInterface
,
6809 IWineD3DDeviceImpl_AddRef
,
6810 IWineD3DDeviceImpl_Release
,
6811 /*** IWineD3DDevice methods ***/
6812 IWineD3DDeviceImpl_GetParent
,
6813 /*** Creation methods**/
6814 IWineD3DDeviceImpl_CreateBuffer
,
6815 IWineD3DDeviceImpl_CreateVertexBuffer
,
6816 IWineD3DDeviceImpl_CreateIndexBuffer
,
6817 IWineD3DDeviceImpl_CreateStateBlock
,
6818 IWineD3DDeviceImpl_CreateSurface
,
6819 IWineD3DDeviceImpl_CreateRendertargetView
,
6820 IWineD3DDeviceImpl_CreateTexture
,
6821 IWineD3DDeviceImpl_CreateVolumeTexture
,
6822 IWineD3DDeviceImpl_CreateVolume
,
6823 IWineD3DDeviceImpl_CreateCubeTexture
,
6824 IWineD3DDeviceImpl_CreateQuery
,
6825 IWineD3DDeviceImpl_CreateSwapChain
,
6826 IWineD3DDeviceImpl_CreateVertexDeclaration
,
6827 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF
,
6828 IWineD3DDeviceImpl_CreateVertexShader
,
6829 IWineD3DDeviceImpl_CreateGeometryShader
,
6830 IWineD3DDeviceImpl_CreatePixelShader
,
6831 IWineD3DDeviceImpl_CreatePalette
,
6832 /*** Odd functions **/
6833 IWineD3DDeviceImpl_Init3D
,
6834 IWineD3DDeviceImpl_InitGDI
,
6835 IWineD3DDeviceImpl_Uninit3D
,
6836 IWineD3DDeviceImpl_UninitGDI
,
6837 IWineD3DDeviceImpl_SetMultithreaded
,
6838 IWineD3DDeviceImpl_EvictManagedResources
,
6839 IWineD3DDeviceImpl_GetAvailableTextureMem
,
6840 IWineD3DDeviceImpl_GetBackBuffer
,
6841 IWineD3DDeviceImpl_GetCreationParameters
,
6842 IWineD3DDeviceImpl_GetDeviceCaps
,
6843 IWineD3DDeviceImpl_GetDirect3D
,
6844 IWineD3DDeviceImpl_GetDisplayMode
,
6845 IWineD3DDeviceImpl_SetDisplayMode
,
6846 IWineD3DDeviceImpl_GetNumberOfSwapChains
,
6847 IWineD3DDeviceImpl_GetRasterStatus
,
6848 IWineD3DDeviceImpl_GetSwapChain
,
6849 IWineD3DDeviceImpl_Reset
,
6850 IWineD3DDeviceImpl_SetDialogBoxMode
,
6851 IWineD3DDeviceImpl_SetCursorProperties
,
6852 IWineD3DDeviceImpl_SetCursorPosition
,
6853 IWineD3DDeviceImpl_ShowCursor
,
6854 /*** Getters and setters **/
6855 IWineD3DDeviceImpl_SetClipPlane
,
6856 IWineD3DDeviceImpl_GetClipPlane
,
6857 IWineD3DDeviceImpl_SetClipStatus
,
6858 IWineD3DDeviceImpl_GetClipStatus
,
6859 IWineD3DDeviceImpl_SetCurrentTexturePalette
,
6860 IWineD3DDeviceImpl_GetCurrentTexturePalette
,
6861 IWineD3DDeviceImpl_SetDepthStencilSurface
,
6862 IWineD3DDeviceImpl_GetDepthStencilSurface
,
6863 IWineD3DDeviceImpl_SetGammaRamp
,
6864 IWineD3DDeviceImpl_GetGammaRamp
,
6865 IWineD3DDeviceImpl_SetIndexBuffer
,
6866 IWineD3DDeviceImpl_GetIndexBuffer
,
6867 IWineD3DDeviceImpl_SetBaseVertexIndex
,
6868 IWineD3DDeviceImpl_GetBaseVertexIndex
,
6869 IWineD3DDeviceImpl_SetLight
,
6870 IWineD3DDeviceImpl_GetLight
,
6871 IWineD3DDeviceImpl_SetLightEnable
,
6872 IWineD3DDeviceImpl_GetLightEnable
,
6873 IWineD3DDeviceImpl_SetMaterial
,
6874 IWineD3DDeviceImpl_GetMaterial
,
6875 IWineD3DDeviceImpl_SetNPatchMode
,
6876 IWineD3DDeviceImpl_GetNPatchMode
,
6877 IWineD3DDeviceImpl_SetPaletteEntries
,
6878 IWineD3DDeviceImpl_GetPaletteEntries
,
6879 IWineD3DDeviceImpl_SetPixelShader
,
6880 IWineD3DDeviceImpl_GetPixelShader
,
6881 IWineD3DDeviceImpl_SetPixelShaderConstantB
,
6882 IWineD3DDeviceImpl_GetPixelShaderConstantB
,
6883 IWineD3DDeviceImpl_SetPixelShaderConstantI
,
6884 IWineD3DDeviceImpl_GetPixelShaderConstantI
,
6885 IWineD3DDeviceImpl_SetPixelShaderConstantF
,
6886 IWineD3DDeviceImpl_GetPixelShaderConstantF
,
6887 IWineD3DDeviceImpl_SetRenderState
,
6888 IWineD3DDeviceImpl_GetRenderState
,
6889 IWineD3DDeviceImpl_SetRenderTarget
,
6890 IWineD3DDeviceImpl_GetRenderTarget
,
6891 IWineD3DDeviceImpl_SetFrontBackBuffers
,
6892 IWineD3DDeviceImpl_SetSamplerState
,
6893 IWineD3DDeviceImpl_GetSamplerState
,
6894 IWineD3DDeviceImpl_SetScissorRect
,
6895 IWineD3DDeviceImpl_GetScissorRect
,
6896 IWineD3DDeviceImpl_SetSoftwareVertexProcessing
,
6897 IWineD3DDeviceImpl_GetSoftwareVertexProcessing
,
6898 IWineD3DDeviceImpl_SetStreamSource
,
6899 IWineD3DDeviceImpl_GetStreamSource
,
6900 IWineD3DDeviceImpl_SetStreamSourceFreq
,
6901 IWineD3DDeviceImpl_GetStreamSourceFreq
,
6902 IWineD3DDeviceImpl_SetTexture
,
6903 IWineD3DDeviceImpl_GetTexture
,
6904 IWineD3DDeviceImpl_SetTextureStageState
,
6905 IWineD3DDeviceImpl_GetTextureStageState
,
6906 IWineD3DDeviceImpl_SetTransform
,
6907 IWineD3DDeviceImpl_GetTransform
,
6908 IWineD3DDeviceImpl_SetVertexDeclaration
,
6909 IWineD3DDeviceImpl_GetVertexDeclaration
,
6910 IWineD3DDeviceImpl_SetVertexShader
,
6911 IWineD3DDeviceImpl_GetVertexShader
,
6912 IWineD3DDeviceImpl_SetVertexShaderConstantB
,
6913 IWineD3DDeviceImpl_GetVertexShaderConstantB
,
6914 IWineD3DDeviceImpl_SetVertexShaderConstantI
,
6915 IWineD3DDeviceImpl_GetVertexShaderConstantI
,
6916 IWineD3DDeviceImpl_SetVertexShaderConstantF
,
6917 IWineD3DDeviceImpl_GetVertexShaderConstantF
,
6918 IWineD3DDeviceImpl_SetViewport
,
6919 IWineD3DDeviceImpl_GetViewport
,
6920 IWineD3DDeviceImpl_MultiplyTransform
,
6921 IWineD3DDeviceImpl_ValidateDevice
,
6922 IWineD3DDeviceImpl_ProcessVertices
,
6923 /*** State block ***/
6924 IWineD3DDeviceImpl_BeginStateBlock
,
6925 IWineD3DDeviceImpl_EndStateBlock
,
6926 /*** Scene management ***/
6927 IWineD3DDeviceImpl_BeginScene
,
6928 IWineD3DDeviceImpl_EndScene
,
6929 IWineD3DDeviceImpl_Present
,
6930 IWineD3DDeviceImpl_Clear
,
6931 IWineD3DDeviceImpl_ClearRendertargetView
,
6933 IWineD3DDeviceImpl_SetPrimitiveType
,
6934 IWineD3DDeviceImpl_GetPrimitiveType
,
6935 IWineD3DDeviceImpl_DrawPrimitive
,
6936 IWineD3DDeviceImpl_DrawIndexedPrimitive
,
6937 IWineD3DDeviceImpl_DrawPrimitiveUP
,
6938 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP
,
6939 IWineD3DDeviceImpl_DrawPrimitiveStrided
,
6940 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided
,
6941 IWineD3DDeviceImpl_DrawRectPatch
,
6942 IWineD3DDeviceImpl_DrawTriPatch
,
6943 IWineD3DDeviceImpl_DeletePatch
,
6944 IWineD3DDeviceImpl_ColorFill
,
6945 IWineD3DDeviceImpl_UpdateTexture
,
6946 IWineD3DDeviceImpl_UpdateSurface
,
6947 IWineD3DDeviceImpl_GetFrontBufferData
,
6948 /*** object tracking ***/
6949 IWineD3DDeviceImpl_EnumResources
6952 HRESULT
device_init(IWineD3DDeviceImpl
*device
, IWineD3DImpl
*wined3d
,
6953 UINT adapter_idx
, WINED3DDEVTYPE device_type
, HWND focus_window
, DWORD flags
,
6954 IUnknown
*parent
, IWineD3DDeviceParent
*device_parent
)
6956 struct wined3d_adapter
*adapter
= &wined3d
->adapters
[adapter_idx
];
6957 const struct fragment_pipeline
*fragment_pipeline
;
6958 struct shader_caps shader_caps
;
6959 struct fragment_caps ffp_caps
;
6960 WINED3DDISPLAYMODE mode
;
6964 device
->lpVtbl
= &IWineD3DDevice_Vtbl
;
6966 device
->wined3d
= (IWineD3D
*)wined3d
;
6967 IWineD3D_AddRef(device
->wined3d
);
6968 device
->adapter
= wined3d
->adapter_count
? adapter
: NULL
;
6969 device
->parent
= parent
;
6970 device
->device_parent
= device_parent
;
6971 list_init(&device
->resources
);
6972 list_init(&device
->shaders
);
6974 device
->surface_alignment
= wined3d
->dxVersion
== 7 ? DDRAW_PITCH_ALIGNMENT
: D3D8_PITCH_ALIGNMENT
;
6975 device
->posFixup
[0] = 1.0f
; /* This is needed to get the x coord unmodified through a MAD. */
6977 /* Get the initial screen setup for ddraw. */
6978 hr
= IWineD3D_GetAdapterDisplayMode((IWineD3D
*)wined3d
, adapter_idx
, &mode
);
6981 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr
);
6982 IWineD3D_Release(device
->wined3d
);
6985 device
->ddraw_width
= mode
.Width
;
6986 device
->ddraw_height
= mode
.Height
;
6987 device
->ddraw_format
= mode
.Format
;
6989 /* Save the creation parameters. */
6990 device
->createParms
.AdapterOrdinal
= adapter_idx
;
6991 device
->createParms
.DeviceType
= device_type
;
6992 device
->createParms
.hFocusWindow
= focus_window
;
6993 device
->createParms
.BehaviorFlags
= flags
;
6995 device
->devType
= device_type
;
6996 for (i
= 0; i
< PATCHMAP_SIZE
; ++i
) list_init(&device
->patches
[i
]);
6998 select_shader_mode(&adapter
->gl_info
, &device
->ps_selected_mode
, &device
->vs_selected_mode
);
6999 device
->shader_backend
= select_shader_backend(adapter
, device_type
);
7001 memset(&shader_caps
, 0, sizeof(shader_caps
));
7002 device
->shader_backend
->shader_get_caps(device_type
, &adapter
->gl_info
, &shader_caps
);
7003 device
->d3d_vshader_constantF
= shader_caps
.MaxVertexShaderConst
;
7004 device
->d3d_pshader_constantF
= shader_caps
.MaxPixelShaderConst
;
7005 device
->vs_clipping
= shader_caps
.VSClipping
;
7007 memset(&ffp_caps
, 0, sizeof(ffp_caps
));
7008 fragment_pipeline
= select_fragment_implementation(adapter
, device_type
);
7009 device
->frag_pipe
= fragment_pipeline
;
7010 fragment_pipeline
->get_caps(device_type
, &adapter
->gl_info
, &ffp_caps
);
7011 device
->max_ffp_textures
= ffp_caps
.MaxSimultaneousTextures
;
7012 device
->max_ffp_texture_stages
= ffp_caps
.MaxTextureBlendStages
;
7014 hr
= compile_state_table(device
->StateTable
, device
->multistate_funcs
, &adapter
->gl_info
,
7015 ffp_vertexstate_template
, fragment_pipeline
, misc_state_template
);
7018 ERR("Failed to compile state table, hr %#x.\n", hr
);
7019 IWineD3D_Release(device
->wined3d
);
7023 device
->blitter
= select_blit_implementation(adapter
, device_type
);
7029 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl
*This
, DWORD state
) {
7030 DWORD rep
= This
->StateTable
[state
].representative
;
7031 struct wined3d_context
*context
;
7036 for(i
= 0; i
< This
->numContexts
; i
++) {
7037 context
= This
->contexts
[i
];
7038 if(isStateDirty(context
, rep
)) continue;
7040 context
->dirtyArray
[context
->numDirtyEntries
++] = rep
;
7041 idx
= rep
/ (sizeof(*context
->isStateDirty
) * CHAR_BIT
);
7042 shift
= rep
& ((sizeof(*context
->isStateDirty
) * CHAR_BIT
) - 1);
7043 context
->isStateDirty
[idx
] |= (1 << shift
);
7047 void get_drawable_size_pbuffer(struct wined3d_context
*context
, UINT
*width
, UINT
*height
)
7049 IWineD3DDeviceImpl
*device
= ((IWineD3DSurfaceImpl
*)context
->current_rt
)->resource
.device
;
7050 /* The drawable size of a pbuffer render target is the current pbuffer size. */
7051 *width
= device
->pbufferWidth
;
7052 *height
= device
->pbufferHeight
;
7055 void get_drawable_size_fbo(struct wined3d_context
*context
, UINT
*width
, UINT
*height
)
7057 IWineD3DSurfaceImpl
*surface
= (IWineD3DSurfaceImpl
*)context
->current_rt
;
7058 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7059 *width
= surface
->pow2Width
;
7060 *height
= surface
->pow2Height
;
7063 void get_drawable_size_backbuffer(struct wined3d_context
*context
, UINT
*width
, UINT
*height
)
7065 IWineD3DSurfaceImpl
*surface
= (IWineD3DSurfaceImpl
*)context
->surface
;
7066 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7067 * current context's drawable, which is the size of the back buffer of the swapchain
7068 * the active context belongs to. The back buffer of the swapchain is stored as the
7069 * surface the context belongs to. */
7070 *width
= surface
->currentDesc
.Width
;
7071 *height
= surface
->currentDesc
.Height
;
7074 LRESULT
device_process_message(IWineD3DDeviceImpl
*device
, HWND window
,
7075 UINT message
, WPARAM wparam
, LPARAM lparam
, WNDPROC proc
)
7077 if (device
->filter_messages
)
7079 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7080 window
, message
, wparam
, lparam
);
7081 return DefWindowProcW(window
, message
, wparam
, lparam
);
7084 if (message
== WM_DESTROY
)
7086 TRACE("unregister window %p.\n", window
);
7087 wined3d_unregister_window(window
);
7089 if (device
->focus_window
== window
) device
->focus_window
= NULL
;
7090 else ERR("Window %p is not the focus window for device %p.\n", window
, device
);
7093 return CallWindowProcW(proc
, window
, message
, wparam
, lparam
);