2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
12 * Copyright 2009 Henri Verbeet for CodeWeavers
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
34 #include "wined3d_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(d3d
);
37 #define GLINFO_LOCATION This->adapter->gl_info
39 /* Define the default light parameters as specified by MSDN */
40 const WINED3DLIGHT WINED3D_default_light
= {
42 WINED3DLIGHT_DIRECTIONAL
, /* Type */
43 { 1.0f
, 1.0f
, 1.0f
, 0.0f
}, /* Diffuse r,g,b,a */
44 { 0.0f
, 0.0f
, 0.0f
, 0.0f
}, /* Specular r,g,b,a */
45 { 0.0f
, 0.0f
, 0.0f
, 0.0f
}, /* Ambient r,g,b,a, */
46 { 0.0f
, 0.0f
, 0.0f
}, /* Position x,y,z */
47 { 0.0f
, 0.0f
, 1.0f
}, /* Direction x,y,z */
50 0.0f
, 0.0f
, 0.0f
, /* Attenuation 0,1,2 */
55 /**********************************************************
56 * Global variable / Constants follow
57 **********************************************************/
58 const float identity
[] =
60 1.0f
, 0.0f
, 0.0f
, 0.0f
,
61 0.0f
, 1.0f
, 0.0f
, 0.0f
,
62 0.0f
, 0.0f
, 1.0f
, 0.0f
,
63 0.0f
, 0.0f
, 0.0f
, 1.0f
,
64 }; /* When needed for comparisons */
66 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
67 * actually have the same values in GL and D3D. */
68 static GLenum
gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type
)
70 switch(primitive_type
)
72 case WINED3DPT_POINTLIST
:
75 case WINED3DPT_LINELIST
:
78 case WINED3DPT_LINESTRIP
:
81 case WINED3DPT_TRIANGLELIST
:
84 case WINED3DPT_TRIANGLESTRIP
:
85 return GL_TRIANGLE_STRIP
;
87 case WINED3DPT_TRIANGLEFAN
:
88 return GL_TRIANGLE_FAN
;
90 case WINED3DPT_LINELIST_ADJ
:
91 return GL_LINES_ADJACENCY_ARB
;
93 case WINED3DPT_LINESTRIP_ADJ
:
94 return GL_LINE_STRIP_ADJACENCY_ARB
;
96 case WINED3DPT_TRIANGLELIST_ADJ
:
97 return GL_TRIANGLES_ADJACENCY_ARB
;
99 case WINED3DPT_TRIANGLESTRIP_ADJ
:
100 return GL_TRIANGLE_STRIP_ADJACENCY_ARB
;
103 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type
));
108 static WINED3DPRIMITIVETYPE
d3d_primitive_type_from_gl(GLenum primitive_type
)
110 switch(primitive_type
)
113 return WINED3DPT_POINTLIST
;
116 return WINED3DPT_LINELIST
;
119 return WINED3DPT_LINESTRIP
;
122 return WINED3DPT_TRIANGLELIST
;
124 case GL_TRIANGLE_STRIP
:
125 return WINED3DPT_TRIANGLESTRIP
;
127 case GL_TRIANGLE_FAN
:
128 return WINED3DPT_TRIANGLEFAN
;
130 case GL_LINES_ADJACENCY_ARB
:
131 return WINED3DPT_LINELIST_ADJ
;
133 case GL_LINE_STRIP_ADJACENCY_ARB
:
134 return WINED3DPT_LINESTRIP_ADJ
;
136 case GL_TRIANGLES_ADJACENCY_ARB
:
137 return WINED3DPT_TRIANGLELIST_ADJ
;
139 case GL_TRIANGLE_STRIP_ADJACENCY_ARB
:
140 return WINED3DPT_TRIANGLESTRIP_ADJ
;
143 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type
));
144 return WINED3DPT_UNDEFINED
;
148 static BOOL
fixed_get_input(BYTE usage
, BYTE usage_idx
, unsigned int *regnum
)
150 if ((usage
== WINED3DDECLUSAGE_POSITION
|| usage
== WINED3DDECLUSAGE_POSITIONT
) && usage_idx
== 0)
151 *regnum
= WINED3D_FFP_POSITION
;
152 else if (usage
== WINED3DDECLUSAGE_BLENDWEIGHT
&& usage_idx
== 0)
153 *regnum
= WINED3D_FFP_BLENDWEIGHT
;
154 else if (usage
== WINED3DDECLUSAGE_BLENDINDICES
&& usage_idx
== 0)
155 *regnum
= WINED3D_FFP_BLENDINDICES
;
156 else if (usage
== WINED3DDECLUSAGE_NORMAL
&& usage_idx
== 0)
157 *regnum
= WINED3D_FFP_NORMAL
;
158 else if (usage
== WINED3DDECLUSAGE_PSIZE
&& usage_idx
== 0)
159 *regnum
= WINED3D_FFP_PSIZE
;
160 else if (usage
== WINED3DDECLUSAGE_COLOR
&& usage_idx
== 0)
161 *regnum
= WINED3D_FFP_DIFFUSE
;
162 else if (usage
== WINED3DDECLUSAGE_COLOR
&& usage_idx
== 1)
163 *regnum
= WINED3D_FFP_SPECULAR
;
164 else if (usage
== WINED3DDECLUSAGE_TEXCOORD
&& usage_idx
< WINED3DDP_MAXTEXCOORD
)
165 *regnum
= WINED3D_FFP_TEXCOORD0
+ usage_idx
;
168 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage
), usage_idx
);
176 /* Context activation is done by the caller. */
177 void device_stream_info_from_declaration(IWineD3DDeviceImpl
*This
,
178 BOOL use_vshader
, struct wined3d_stream_info
*stream_info
, BOOL
*fixup
)
180 /* We need to deal with frequency data! */
181 IWineD3DVertexDeclarationImpl
*declaration
= (IWineD3DVertexDeclarationImpl
*)This
->stateBlock
->vertexDecl
;
182 UINT stream_count
= This
->stateBlock
->streamIsUP
? 0 : declaration
->num_streams
;
183 const DWORD
*streams
= declaration
->streams
;
186 stream_info
->use_map
= 0;
187 stream_info
->swizzle_map
= 0;
189 /* Check for transformed vertices, disable vertex shader if present. */
190 stream_info
->position_transformed
= declaration
->position_transformed
;
191 if (declaration
->position_transformed
) use_vshader
= FALSE
;
193 /* Translate the declaration into strided data. */
194 for (i
= 0; i
< declaration
->element_count
; ++i
)
196 const struct wined3d_vertex_declaration_element
*element
= &declaration
->elements
[i
];
197 GLuint buffer_object
= 0;
198 const BYTE
*data
= NULL
;
203 TRACE("%p Element %p (%u of %u)\n", declaration
->elements
,
204 element
, i
+ 1, declaration
->element_count
);
206 if (!This
->stateBlock
->streamSource
[element
->input_slot
]) continue;
208 stride
= This
->stateBlock
->streamStride
[element
->input_slot
];
209 if (This
->stateBlock
->streamIsUP
)
211 TRACE("Stream %u is UP, %p\n", element
->input_slot
, This
->stateBlock
->streamSource
[element
->input_slot
]);
213 data
= (BYTE
*)This
->stateBlock
->streamSource
[element
->input_slot
];
217 TRACE("Stream %u isn't UP, %p\n", element
->input_slot
, This
->stateBlock
->streamSource
[element
->input_slot
]);
218 data
= buffer_get_memory(This
->stateBlock
->streamSource
[element
->input_slot
], 0, &buffer_object
);
220 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
221 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
222 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
223 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
224 * not, drawStridedSlow is needed, including a vertex buffer path. */
225 if (This
->stateBlock
->loadBaseVertexIndex
< 0)
227 WARN("loadBaseVertexIndex is < 0 (%d), not using vbos\n", This
->stateBlock
->loadBaseVertexIndex
);
229 data
= buffer_get_sysmem((struct wined3d_buffer
*)This
->stateBlock
->streamSource
[element
->input_slot
]);
230 if ((UINT_PTR
)data
< -This
->stateBlock
->loadBaseVertexIndex
* stride
)
232 FIXME("System memory vertex data load offset is negative!\n");
238 if (buffer_object
) *fixup
= TRUE
;
239 else if (*fixup
&& !use_vshader
240 && (element
->usage
== WINED3DDECLUSAGE_COLOR
241 || element
->usage
== WINED3DDECLUSAGE_POSITIONT
))
243 static BOOL warned
= FALSE
;
246 /* This may be bad with the fixed function pipeline. */
247 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
253 data
+= element
->offset
;
255 TRACE("offset %u input_slot %u usage_idx %d\n", element
->offset
, element
->input_slot
, element
->usage_idx
);
259 if (element
->output_slot
== ~0U)
261 /* TODO: Assuming vertexdeclarations are usually used with the
262 * same or a similar shader, it might be worth it to store the
263 * last used output slot and try that one first. */
264 stride_used
= vshader_get_input(This
->stateBlock
->vertexShader
,
265 element
->usage
, element
->usage_idx
, &idx
);
269 idx
= element
->output_slot
;
275 if (!element
->ffp_valid
)
277 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
278 debug_d3dformat(element
->format_desc
->format
), debug_d3ddeclusage(element
->usage
));
283 stride_used
= fixed_get_input(element
->usage
, element
->usage_idx
, &idx
);
289 TRACE("Load %s array %u [usage %s, usage_idx %u, "
290 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
291 use_vshader
? "shader": "fixed function", idx
,
292 debug_d3ddeclusage(element
->usage
), element
->usage_idx
, element
->input_slot
,
293 element
->offset
, stride
, debug_d3dformat(element
->format_desc
->format
), buffer_object
);
295 stream_info
->elements
[idx
].format_desc
= element
->format_desc
;
296 stream_info
->elements
[idx
].stride
= stride
;
297 stream_info
->elements
[idx
].data
= data
;
298 stream_info
->elements
[idx
].stream_idx
= element
->input_slot
;
299 stream_info
->elements
[idx
].buffer_object
= buffer_object
;
301 if (!This
->adapter
->gl_info
.supported
[EXT_VERTEX_ARRAY_BGRA
]
302 && element
->format_desc
->format
== WINED3DFMT_B8G8R8A8_UNORM
)
304 stream_info
->swizzle_map
|= 1 << idx
;
306 stream_info
->use_map
|= 1 << idx
;
310 /* Now call PreLoad on all the vertex buffers. In the very rare case
311 * that the buffers stopps converting PreLoad will dirtify the VDECL again.
312 * The vertex buffer can now use the strided structure in the device instead of finding its
315 * NULL streams won't be recorded in the array, UP streams won't be either. A stream is only
317 for (i
= 0; i
< stream_count
; ++i
)
319 IWineD3DBuffer
*vb
= This
->stateBlock
->streamSource
[streams
[i
]];
320 if (vb
) IWineD3DBuffer_PreLoad(vb
);
324 static void stream_info_element_from_strided(const struct wined3d_gl_info
*gl_info
,
325 const struct WineDirect3DStridedData
*strided
, struct wined3d_stream_info_element
*e
)
327 const struct GlPixelFormatDesc
*format_desc
= getFormatDescEntry(strided
->format
, gl_info
);
328 e
->format_desc
= format_desc
;
329 e
->stride
= strided
->dwStride
;
330 e
->data
= strided
->lpData
;
332 e
->buffer_object
= 0;
335 void device_stream_info_from_strided(const struct wined3d_gl_info
*gl_info
,
336 const struct WineDirect3DVertexStridedData
*strided
, struct wined3d_stream_info
*stream_info
)
340 memset(stream_info
, 0, sizeof(*stream_info
));
342 if (strided
->position
.lpData
)
343 stream_info_element_from_strided(gl_info
, &strided
->position
, &stream_info
->elements
[WINED3D_FFP_POSITION
]);
344 if (strided
->normal
.lpData
)
345 stream_info_element_from_strided(gl_info
, &strided
->normal
, &stream_info
->elements
[WINED3D_FFP_NORMAL
]);
346 if (strided
->diffuse
.lpData
)
347 stream_info_element_from_strided(gl_info
, &strided
->diffuse
, &stream_info
->elements
[WINED3D_FFP_DIFFUSE
]);
348 if (strided
->specular
.lpData
)
349 stream_info_element_from_strided(gl_info
, &strided
->specular
, &stream_info
->elements
[WINED3D_FFP_SPECULAR
]);
351 for (i
= 0; i
< WINED3DDP_MAXTEXCOORD
; ++i
)
353 if (strided
->texCoords
[i
].lpData
)
354 stream_info_element_from_strided(gl_info
, &strided
->texCoords
[i
],
355 &stream_info
->elements
[WINED3D_FFP_TEXCOORD0
+ i
]);
358 stream_info
->position_transformed
= strided
->position_transformed
;
360 for (i
= 0; i
< sizeof(stream_info
->elements
) / sizeof(*stream_info
->elements
); ++i
)
362 if (!stream_info
->elements
[i
].format_desc
) continue;
364 if (!gl_info
->supported
[EXT_VERTEX_ARRAY_BGRA
]
365 && stream_info
->elements
[i
].format_desc
->format
== WINED3DFMT_B8G8R8A8_UNORM
)
367 stream_info
->swizzle_map
|= 1 << i
;
369 stream_info
->use_map
|= 1 << i
;
373 /**********************************************************
374 * IUnknown parts follows
375 **********************************************************/
377 static HRESULT WINAPI
IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice
*iface
,REFIID riid
,LPVOID
*ppobj
)
379 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
381 TRACE("(%p)->(%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
382 if (IsEqualGUID(riid
, &IID_IUnknown
)
383 || IsEqualGUID(riid
, &IID_IWineD3DBase
)
384 || IsEqualGUID(riid
, &IID_IWineD3DDevice
)) {
385 IUnknown_AddRef(iface
);
390 return E_NOINTERFACE
;
393 static ULONG WINAPI
IWineD3DDeviceImpl_AddRef(IWineD3DDevice
*iface
) {
394 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
395 ULONG refCount
= InterlockedIncrement(&This
->ref
);
397 TRACE("(%p) : AddRef increasing from %d\n", This
, refCount
- 1);
401 static ULONG WINAPI
IWineD3DDeviceImpl_Release(IWineD3DDevice
*iface
) {
402 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
403 ULONG refCount
= InterlockedDecrement(&This
->ref
);
405 TRACE("(%p) : Releasing from %d\n", This
, refCount
+ 1);
410 for (i
= 0; i
< sizeof(This
->multistate_funcs
)/sizeof(This
->multistate_funcs
[0]); ++i
) {
411 HeapFree(GetProcessHeap(), 0, This
->multistate_funcs
[i
]);
412 This
->multistate_funcs
[i
] = NULL
;
415 /* TODO: Clean up all the surfaces and textures! */
416 /* NOTE: You must release the parent if the object was created via a callback
417 ** ***************************/
419 if (!list_empty(&This
->resources
)) {
420 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This
);
421 dumpResources(&This
->resources
);
424 if(This
->contexts
) ERR("Context array not freed!\n");
425 if (This
->hardwareCursor
) DestroyCursor(This
->hardwareCursor
);
426 This
->haveHardwareCursor
= FALSE
;
428 IWineD3D_Release(This
->wined3d
);
429 This
->wined3d
= NULL
;
430 HeapFree(GetProcessHeap(), 0, This
);
431 TRACE("Freed device %p\n", This
);
437 /**********************************************************
438 * IWineD3DDevice implementation follows
439 **********************************************************/
440 static HRESULT WINAPI
IWineD3DDeviceImpl_GetParent(IWineD3DDevice
*iface
, IUnknown
**pParent
) {
441 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
442 *pParent
= This
->parent
;
443 IUnknown_AddRef(This
->parent
);
447 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice
*iface
, struct wined3d_buffer_desc
*desc
,
448 const void *data
, IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
, IWineD3DBuffer
**buffer
)
450 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
451 struct wined3d_buffer
*object
;
454 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface
, desc
, data
, parent
, buffer
);
456 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
459 ERR("Failed to allocate memory\n");
460 return E_OUTOFMEMORY
;
463 FIXME("Ignoring access flags (pool)\n");
465 hr
= buffer_init(object
, This
, desc
->byte_width
, desc
->usage
, WINED3DFMT_UNKNOWN
,
466 WINED3DPOOL_MANAGED
, GL_ARRAY_BUFFER_ARB
, data
, parent
, parent_ops
);
469 WARN("Failed to initialize buffer, hr %#x.\n", hr
);
470 HeapFree(GetProcessHeap(), 0, object
);
473 object
->desc
= *desc
;
475 TRACE("Created buffer %p.\n", object
);
477 *buffer
= (IWineD3DBuffer
*)object
;
482 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice
*iface
,
483 UINT Size
, DWORD Usage
, WINED3DPOOL Pool
, IWineD3DBuffer
**ppVertexBuffer
,
484 IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
)
486 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
487 struct wined3d_buffer
*object
;
490 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
491 iface
, Size
, Usage
, Pool
, ppVertexBuffer
, parent
, parent_ops
);
493 if (Pool
== WINED3DPOOL_SCRATCH
)
495 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
496 * anyway, SCRATCH vertex buffers aren't usable anywhere
498 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
499 *ppVertexBuffer
= NULL
;
500 return WINED3DERR_INVALIDCALL
;
503 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
506 ERR("Out of memory\n");
507 *ppVertexBuffer
= NULL
;
508 return WINED3DERR_OUTOFVIDEOMEMORY
;
511 hr
= buffer_init(object
, This
, Size
, Usage
, WINED3DFMT_VERTEXDATA
,
512 Pool
, GL_ARRAY_BUFFER_ARB
, NULL
, parent
, parent_ops
);
515 WARN("Failed to initialize buffer, hr %#x.\n", hr
);
516 HeapFree(GetProcessHeap(), 0, object
);
520 TRACE("Created buffer %p.\n", object
);
521 *ppVertexBuffer
= (IWineD3DBuffer
*)object
;
526 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice
*iface
,
527 UINT Length
, DWORD Usage
, WINED3DPOOL Pool
, IWineD3DBuffer
**ppIndexBuffer
,
528 IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
)
530 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
531 struct wined3d_buffer
*object
;
534 TRACE("(%p) Creating index buffer\n", This
);
536 /* Allocate the storage for the device */
537 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
540 ERR("Out of memory\n");
541 *ppIndexBuffer
= NULL
;
542 return WINED3DERR_OUTOFVIDEOMEMORY
;
545 hr
= buffer_init(object
, This
, Length
, Usage
| WINED3DUSAGE_STATICDECL
,
546 WINED3DFMT_UNKNOWN
, Pool
, GL_ELEMENT_ARRAY_BUFFER_ARB
, NULL
,
550 WARN("Failed to initialize buffer, hr %#x\n", hr
);
551 HeapFree(GetProcessHeap(), 0, object
);
555 TRACE("Created buffer %p.\n", object
);
557 *ppIndexBuffer
= (IWineD3DBuffer
*) object
;
562 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice
*iface
,
563 WINED3DSTATEBLOCKTYPE type
, IWineD3DStateBlock
**stateblock
, IUnknown
*parent
)
565 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
566 IWineD3DStateBlockImpl
*object
;
569 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
572 ERR("Failed to allocate stateblock memory.\n");
573 return E_OUTOFMEMORY
;
576 hr
= stateblock_init(object
, This
, type
);
579 WARN("Failed to initialize stateblock, hr %#x.\n", hr
);
580 HeapFree(GetProcessHeap(), 0, object
);
584 TRACE("Created stateblock %p.\n", object
);
585 *stateblock
= (IWineD3DStateBlock
*)object
;
590 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice
*iface
, UINT Width
, UINT Height
,
591 WINED3DFORMAT Format
, BOOL Lockable
, BOOL Discard
, UINT Level
, IWineD3DSurface
**ppSurface
,
592 DWORD Usage
, WINED3DPOOL Pool
, WINED3DMULTISAMPLE_TYPE MultiSample
, DWORD MultisampleQuality
,
593 WINED3DSURFTYPE Impl
, IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
)
595 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
596 IWineD3DSurfaceImpl
*object
;
599 TRACE("(%p) Create surface\n",This
);
601 if (Impl
== SURFACE_OPENGL
&& !This
->adapter
)
603 ERR("OpenGL surfaces are not available without OpenGL.\n");
604 return WINED3DERR_NOTAVAILABLE
;
607 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
610 ERR("Failed to allocate surface memory.\n");
611 return WINED3DERR_OUTOFVIDEOMEMORY
;
614 hr
= surface_init(object
, Impl
, This
->surface_alignment
, Width
, Height
, Level
, Lockable
,
615 Discard
, MultiSample
, MultisampleQuality
, This
, Usage
, Format
, Pool
, parent
, parent_ops
);
618 WARN("Failed to initialize surface, returning %#x.\n", hr
);
619 HeapFree(GetProcessHeap(), 0, object
);
623 TRACE("(%p) : Created surface %p\n", This
, object
);
625 *ppSurface
= (IWineD3DSurface
*)object
;
630 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice
*iface
,
631 IWineD3DResource
*resource
, IUnknown
*parent
, IWineD3DRendertargetView
**rendertarget_view
)
633 struct wined3d_rendertarget_view
*object
;
635 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
638 ERR("Failed to allocate memory\n");
639 return E_OUTOFMEMORY
;
642 object
->vtbl
= &wined3d_rendertarget_view_vtbl
;
643 object
->refcount
= 1;
644 IWineD3DResource_AddRef(resource
);
645 object
->resource
= resource
;
646 object
->parent
= parent
;
648 *rendertarget_view
= (IWineD3DRendertargetView
*)object
;
653 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice
*iface
,
654 UINT Width
, UINT Height
, UINT Levels
, DWORD Usage
, WINED3DFORMAT Format
, WINED3DPOOL Pool
,
655 IWineD3DTexture
**ppTexture
, IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
)
657 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
658 IWineD3DTextureImpl
*object
;
661 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This
, Width
, Height
, Levels
, Usage
);
662 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
663 Format
, debug_d3dformat(Format
), Pool
, ppTexture
, parent
);
665 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
668 ERR("Out of memory\n");
670 return WINED3DERR_OUTOFVIDEOMEMORY
;
673 hr
= texture_init(object
, Width
, Height
, Levels
, This
, Usage
, Format
, Pool
, parent
, parent_ops
);
676 WARN("Failed to initialize texture, returning %#x\n", hr
);
677 HeapFree(GetProcessHeap(), 0, object
);
682 *ppTexture
= (IWineD3DTexture
*)object
;
684 TRACE("(%p) : Created texture %p\n", This
, object
);
689 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice
*iface
,
690 UINT Width
, UINT Height
, UINT Depth
, UINT Levels
, DWORD Usage
, WINED3DFORMAT Format
, WINED3DPOOL Pool
,
691 IWineD3DVolumeTexture
**ppVolumeTexture
, IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
)
693 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
694 IWineD3DVolumeTextureImpl
*object
;
697 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
698 Depth
, Levels
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
700 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
703 ERR("Out of memory\n");
704 *ppVolumeTexture
= NULL
;
705 return WINED3DERR_OUTOFVIDEOMEMORY
;
708 hr
= volumetexture_init(object
, Width
, Height
, Depth
, Levels
, This
, Usage
, Format
, Pool
, parent
, parent_ops
);
711 WARN("Failed to initialize volumetexture, returning %#x\n", hr
);
712 HeapFree(GetProcessHeap(), 0, object
);
713 *ppVolumeTexture
= NULL
;
717 TRACE("(%p) : Created volume texture %p.\n", This
, object
);
718 *ppVolumeTexture
= (IWineD3DVolumeTexture
*)object
;
723 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice
*iface
, UINT Width
, UINT Height
,
724 UINT Depth
, DWORD Usage
, WINED3DFORMAT Format
, WINED3DPOOL Pool
, IWineD3DVolume
**ppVolume
,
725 IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
)
727 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
728 IWineD3DVolumeImpl
*object
;
731 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
732 Depth
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
734 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
737 ERR("Out of memory\n");
739 return WINED3DERR_OUTOFVIDEOMEMORY
;
742 hr
= volume_init(object
, This
, Width
, Height
, Depth
, Usage
, Format
, Pool
, parent
, parent_ops
);
745 WARN("Failed to initialize volume, returning %#x.\n", hr
);
746 HeapFree(GetProcessHeap(), 0, object
);
750 TRACE("(%p) : Created volume %p.\n", This
, object
);
751 *ppVolume
= (IWineD3DVolume
*)object
;
756 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice
*iface
, UINT EdgeLength
, UINT Levels
,
757 DWORD Usage
, WINED3DFORMAT Format
, WINED3DPOOL Pool
, IWineD3DCubeTexture
**ppCubeTexture
,
758 IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
)
760 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
761 IWineD3DCubeTextureImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
764 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
767 ERR("Out of memory\n");
768 *ppCubeTexture
= NULL
;
769 return WINED3DERR_OUTOFVIDEOMEMORY
;
772 hr
= cubetexture_init(object
, EdgeLength
, Levels
, This
, Usage
, Format
, Pool
, parent
, parent_ops
);
775 WARN("Failed to initialize cubetexture, returning %#x\n", hr
);
776 HeapFree(GetProcessHeap(), 0, object
);
777 *ppCubeTexture
= NULL
;
781 TRACE("(%p) : Created Cube Texture %p\n", This
, object
);
782 *ppCubeTexture
= (IWineD3DCubeTexture
*)object
;
787 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice
*iface
, WINED3DQUERYTYPE Type
, IWineD3DQuery
**ppQuery
, IUnknown
* parent
) {
788 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
789 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
790 IWineD3DQueryImpl
*object
; /*NOTE: impl ref allowed since this is a create function */
791 HRESULT hr
= WINED3DERR_NOTAVAILABLE
;
792 const IWineD3DQueryVtbl
*vtable
;
794 /* Just a check to see if we support this type of query */
796 case WINED3DQUERYTYPE_OCCLUSION
:
797 TRACE("(%p) occlusion query\n", This
);
798 if (gl_info
->supported
[ARB_OCCLUSION_QUERY
])
801 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
803 vtable
= &IWineD3DOcclusionQuery_Vtbl
;
806 case WINED3DQUERYTYPE_EVENT
:
807 if (!gl_info
->supported
[NV_FENCE
] && !gl_info
->supported
[APPLE_FENCE
])
809 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
810 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
812 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This
);
814 vtable
= &IWineD3DEventQuery_Vtbl
;
818 case WINED3DQUERYTYPE_VCACHE
:
819 case WINED3DQUERYTYPE_RESOURCEMANAGER
:
820 case WINED3DQUERYTYPE_VERTEXSTATS
:
821 case WINED3DQUERYTYPE_TIMESTAMP
:
822 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT
:
823 case WINED3DQUERYTYPE_TIMESTAMPFREQ
:
824 case WINED3DQUERYTYPE_PIPELINETIMINGS
:
825 case WINED3DQUERYTYPE_INTERFACETIMINGS
:
826 case WINED3DQUERYTYPE_VERTEXTIMINGS
:
827 case WINED3DQUERYTYPE_PIXELTIMINGS
:
828 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS
:
829 case WINED3DQUERYTYPE_CACHEUTILIZATION
:
831 /* Use the base Query vtable until we have a special one for each query */
832 vtable
= &IWineD3DQuery_Vtbl
;
833 FIXME("(%p) Unhandled query type %d\n", This
, Type
);
835 if(NULL
== ppQuery
|| hr
!= WINED3D_OK
) {
839 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
842 ERR("Out of memory\n");
844 return WINED3DERR_OUTOFVIDEOMEMORY
;
847 object
->lpVtbl
= vtable
;
849 object
->state
= QUERY_CREATED
;
850 object
->device
= This
;
851 object
->parent
= parent
;
854 *ppQuery
= (IWineD3DQuery
*)object
;
856 /* allocated the 'extended' data based on the type of query requested */
858 case WINED3DQUERYTYPE_OCCLUSION
:
859 object
->extendedData
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_occlusion_query
));
860 ((struct wined3d_occlusion_query
*)object
->extendedData
)->context
= NULL
;
863 case WINED3DQUERYTYPE_EVENT
:
864 object
->extendedData
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_event_query
));
865 ((struct wined3d_event_query
*)object
->extendedData
)->context
= NULL
;
868 case WINED3DQUERYTYPE_VCACHE
:
869 case WINED3DQUERYTYPE_RESOURCEMANAGER
:
870 case WINED3DQUERYTYPE_VERTEXSTATS
:
871 case WINED3DQUERYTYPE_TIMESTAMP
:
872 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT
:
873 case WINED3DQUERYTYPE_TIMESTAMPFREQ
:
874 case WINED3DQUERYTYPE_PIPELINETIMINGS
:
875 case WINED3DQUERYTYPE_INTERFACETIMINGS
:
876 case WINED3DQUERYTYPE_VERTEXTIMINGS
:
877 case WINED3DQUERYTYPE_PIXELTIMINGS
:
878 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS
:
879 case WINED3DQUERYTYPE_CACHEUTILIZATION
:
881 object
->extendedData
= 0;
882 FIXME("(%p) Unhandled query type %d\n",This
, Type
);
884 TRACE("(%p) : Created Query %p\n", This
, object
);
888 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice
*iface
,
889 WINED3DPRESENT_PARAMETERS
*present_parameters
, IWineD3DSwapChain
**swapchain
,
890 IUnknown
*parent
, WINED3DSURFTYPE surface_type
)
892 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
893 IWineD3DSwapChainImpl
*object
;
896 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
897 iface
, present_parameters
, swapchain
, parent
, surface_type
);
899 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
902 ERR("Failed to allocate swapchain memory.\n");
903 return E_OUTOFMEMORY
;
906 hr
= swapchain_init(object
, surface_type
, This
, present_parameters
, parent
);
909 WARN("Failed to initialize swapchain, hr %#x.\n", hr
);
910 HeapFree(GetProcessHeap(), 0, object
);
914 TRACE("Created swapchain %p.\n", object
);
915 *swapchain
= (IWineD3DSwapChain
*)object
;
920 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
921 static UINT WINAPI
IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice
*iface
) {
922 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
923 TRACE("(%p)\n", This
);
925 return This
->NumberOfSwapChains
;
928 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice
*iface
, UINT iSwapChain
, IWineD3DSwapChain
**pSwapChain
) {
929 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
930 TRACE("(%p) : swapchain %d\n", This
, iSwapChain
);
932 if(iSwapChain
< This
->NumberOfSwapChains
) {
933 *pSwapChain
= This
->swapchains
[iSwapChain
];
934 IWineD3DSwapChain_AddRef(*pSwapChain
);
935 TRACE("(%p) returning %p\n", This
, *pSwapChain
);
938 TRACE("Swapchain out of range\n");
940 return WINED3DERR_INVALIDCALL
;
944 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice
*iface
,
945 IWineD3DVertexDeclaration
**declaration
, IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
,
946 const WINED3DVERTEXELEMENT
*elements
, UINT element_count
)
948 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
949 IWineD3DVertexDeclarationImpl
*object
= NULL
;
952 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
953 iface
, declaration
, parent
, elements
, element_count
);
955 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
958 ERR("Failed to allocate vertex declaration memory.\n");
959 return E_OUTOFMEMORY
;
962 hr
= vertexdeclaration_init(object
, This
, elements
, element_count
, parent
, parent_ops
);
965 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr
);
966 HeapFree(GetProcessHeap(), 0, object
);
970 TRACE("Created vertex declaration %p.\n", object
);
971 *declaration
= (IWineD3DVertexDeclaration
*)object
;
976 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl
*This
, /* For the GL info, which has the type table */
977 DWORD fvf
, WINED3DVERTEXELEMENT
** ppVertexElements
) {
979 unsigned int idx
, idx2
;
981 BOOL has_pos
= (fvf
& WINED3DFVF_POSITION_MASK
) != 0;
982 BOOL has_blend
= (fvf
& WINED3DFVF_XYZB5
) > WINED3DFVF_XYZRHW
;
983 BOOL has_blend_idx
= has_blend
&&
984 (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB5
) ||
985 (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
) ||
986 (fvf
& WINED3DFVF_LASTBETA_UBYTE4
));
987 BOOL has_normal
= (fvf
& WINED3DFVF_NORMAL
) != 0;
988 BOOL has_psize
= (fvf
& WINED3DFVF_PSIZE
) != 0;
989 BOOL has_diffuse
= (fvf
& WINED3DFVF_DIFFUSE
) != 0;
990 BOOL has_specular
= (fvf
& WINED3DFVF_SPECULAR
) !=0;
992 DWORD num_textures
= (fvf
& WINED3DFVF_TEXCOUNT_MASK
) >> WINED3DFVF_TEXCOUNT_SHIFT
;
993 DWORD texcoords
= (fvf
& 0xFFFF0000) >> 16;
994 WINED3DVERTEXELEMENT
*elements
= NULL
;
997 DWORD num_blends
= 1 + (((fvf
& WINED3DFVF_XYZB5
) - WINED3DFVF_XYZB1
) >> 1);
998 if (has_blend_idx
) num_blends
--;
1000 /* Compute declaration size */
1001 size
= has_pos
+ (has_blend
&& num_blends
> 0) + has_blend_idx
+ has_normal
+
1002 has_psize
+ has_diffuse
+ has_specular
+ num_textures
;
1004 /* convert the declaration */
1005 elements
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WINED3DVERTEXELEMENT
));
1006 if (!elements
) return ~0U;
1010 if (!has_blend
&& (fvf
& WINED3DFVF_XYZRHW
)) {
1011 elements
[idx
].format
= WINED3DFMT_R32G32B32A32_FLOAT
;
1012 elements
[idx
].usage
= WINED3DDECLUSAGE_POSITIONT
;
1014 else if ((fvf
& WINED3DFVF_XYZW
) == WINED3DFVF_XYZW
) {
1015 elements
[idx
].format
= WINED3DFMT_R32G32B32A32_FLOAT
;
1016 elements
[idx
].usage
= WINED3DDECLUSAGE_POSITION
;
1019 elements
[idx
].format
= WINED3DFMT_R32G32B32_FLOAT
;
1020 elements
[idx
].usage
= WINED3DDECLUSAGE_POSITION
;
1022 elements
[idx
].usage_idx
= 0;
1025 if (has_blend
&& (num_blends
> 0)) {
1026 if (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB2
) && (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
))
1027 elements
[idx
].format
= WINED3DFMT_B8G8R8A8_UNORM
;
1029 switch(num_blends
) {
1030 case 1: elements
[idx
].format
= WINED3DFMT_R32_FLOAT
; break;
1031 case 2: elements
[idx
].format
= WINED3DFMT_R32G32_FLOAT
; break;
1032 case 3: elements
[idx
].format
= WINED3DFMT_R32G32B32_FLOAT
; break;
1033 case 4: elements
[idx
].format
= WINED3DFMT_R32G32B32A32_FLOAT
; break;
1035 ERR("Unexpected amount of blend values: %u\n", num_blends
);
1038 elements
[idx
].usage
= WINED3DDECLUSAGE_BLENDWEIGHT
;
1039 elements
[idx
].usage_idx
= 0;
1042 if (has_blend_idx
) {
1043 if (fvf
& WINED3DFVF_LASTBETA_UBYTE4
||
1044 (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB2
) && (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
)))
1045 elements
[idx
].format
= WINED3DFMT_R8G8B8A8_UINT
;
1046 else if (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
)
1047 elements
[idx
].format
= WINED3DFMT_B8G8R8A8_UNORM
;
1049 elements
[idx
].format
= WINED3DFMT_R32_FLOAT
;
1050 elements
[idx
].usage
= WINED3DDECLUSAGE_BLENDINDICES
;
1051 elements
[idx
].usage_idx
= 0;
1055 elements
[idx
].format
= WINED3DFMT_R32G32B32_FLOAT
;
1056 elements
[idx
].usage
= WINED3DDECLUSAGE_NORMAL
;
1057 elements
[idx
].usage_idx
= 0;
1061 elements
[idx
].format
= WINED3DFMT_R32_FLOAT
;
1062 elements
[idx
].usage
= WINED3DDECLUSAGE_PSIZE
;
1063 elements
[idx
].usage_idx
= 0;
1067 elements
[idx
].format
= WINED3DFMT_B8G8R8A8_UNORM
;
1068 elements
[idx
].usage
= WINED3DDECLUSAGE_COLOR
;
1069 elements
[idx
].usage_idx
= 0;
1073 elements
[idx
].format
= WINED3DFMT_B8G8R8A8_UNORM
;
1074 elements
[idx
].usage
= WINED3DDECLUSAGE_COLOR
;
1075 elements
[idx
].usage_idx
= 1;
1078 for (idx2
= 0; idx2
< num_textures
; idx2
++) {
1079 unsigned int numcoords
= (texcoords
>> (idx2
*2)) & 0x03;
1080 switch (numcoords
) {
1081 case WINED3DFVF_TEXTUREFORMAT1
:
1082 elements
[idx
].format
= WINED3DFMT_R32_FLOAT
;
1084 case WINED3DFVF_TEXTUREFORMAT2
:
1085 elements
[idx
].format
= WINED3DFMT_R32G32_FLOAT
;
1087 case WINED3DFVF_TEXTUREFORMAT3
:
1088 elements
[idx
].format
= WINED3DFMT_R32G32B32_FLOAT
;
1090 case WINED3DFVF_TEXTUREFORMAT4
:
1091 elements
[idx
].format
= WINED3DFMT_R32G32B32A32_FLOAT
;
1094 elements
[idx
].usage
= WINED3DDECLUSAGE_TEXCOORD
;
1095 elements
[idx
].usage_idx
= idx2
;
1099 /* Now compute offsets, and initialize the rest of the fields */
1100 for (idx
= 0, offset
= 0; idx
< size
; ++idx
)
1102 const struct GlPixelFormatDesc
*format_desc
= getFormatDescEntry(elements
[idx
].format
, &This
->adapter
->gl_info
);
1103 elements
[idx
].input_slot
= 0;
1104 elements
[idx
].method
= WINED3DDECLMETHOD_DEFAULT
;
1105 elements
[idx
].offset
= offset
;
1106 offset
+= format_desc
->component_count
* format_desc
->component_size
;
1109 *ppVertexElements
= elements
;
1113 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice
*iface
,
1114 IWineD3DVertexDeclaration
**declaration
, IUnknown
*parent
,
1115 const struct wined3d_parent_ops
*parent_ops
, DWORD fvf
)
1117 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1118 WINED3DVERTEXELEMENT
*elements
;
1122 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface
, declaration
, parent
, fvf
);
1124 size
= ConvertFvfToDeclaration(This
, fvf
, &elements
);
1125 if (size
== ~0U) return E_OUTOFMEMORY
;
1127 hr
= IWineD3DDevice_CreateVertexDeclaration(iface
, declaration
, parent
, parent_ops
, elements
, size
);
1128 HeapFree(GetProcessHeap(), 0, elements
);
1132 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice
*iface
,
1133 const DWORD
*pFunction
, const struct wined3d_shader_signature
*output_signature
,
1134 IWineD3DVertexShader
**ppVertexShader
, IUnknown
*parent
,
1135 const struct wined3d_parent_ops
*parent_ops
)
1137 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1138 IWineD3DVertexShaderImpl
*object
;
1141 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1144 ERR("Failed to allocate shader memory.\n");
1145 return E_OUTOFMEMORY
;
1148 hr
= vertexshader_init(object
, This
, pFunction
, output_signature
, parent
, parent_ops
);
1151 WARN("Failed to initialize vertex shader, hr %#x.\n", hr
);
1152 HeapFree(GetProcessHeap(), 0, object
);
1156 TRACE("Created vertex shader %p.\n", object
);
1157 *ppVertexShader
= (IWineD3DVertexShader
*)object
;
1162 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice
*iface
,
1163 const DWORD
*byte_code
, const struct wined3d_shader_signature
*output_signature
,
1164 IWineD3DGeometryShader
**shader
, IUnknown
*parent
,
1165 const struct wined3d_parent_ops
*parent_ops
)
1167 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1168 struct wined3d_geometryshader
*object
;
1171 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1174 ERR("Failed to allocate shader memory.\n");
1175 return E_OUTOFMEMORY
;
1178 hr
= geometryshader_init(object
, This
, byte_code
, output_signature
, parent
, parent_ops
);
1181 WARN("Failed to initialize geometry shader, hr %#x.\n", hr
);
1182 HeapFree(GetProcessHeap(), 0, object
);
1186 TRACE("Created geometry shader %p.\n", object
);
1187 *shader
= (IWineD3DGeometryShader
*)object
;
1192 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice
*iface
,
1193 const DWORD
*pFunction
, const struct wined3d_shader_signature
*output_signature
,
1194 IWineD3DPixelShader
**ppPixelShader
, IUnknown
*parent
,
1195 const struct wined3d_parent_ops
*parent_ops
)
1197 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1198 IWineD3DPixelShaderImpl
*object
;
1201 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1204 ERR("Failed to allocate shader memory.\n");
1205 return E_OUTOFMEMORY
;
1208 hr
= pixelshader_init(object
, This
, pFunction
, output_signature
, parent
, parent_ops
);
1211 WARN("Failed to initialize pixel shader, hr %#x.\n", hr
);
1212 HeapFree(GetProcessHeap(), 0, object
);
1216 TRACE("Created pixel shader %p.\n", object
);
1217 *ppPixelShader
= (IWineD3DPixelShader
*)object
;
1222 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice
*iface
, DWORD Flags
,
1223 const PALETTEENTRY
*PalEnt
, IWineD3DPalette
**Palette
, IUnknown
*Parent
)
1225 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1226 IWineD3DPaletteImpl
*object
;
1228 TRACE("(%p)->(%x, %p, %p, %p)\n", This
, Flags
, PalEnt
, Palette
, Parent
);
1230 /* Create the new object */
1231 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DPaletteImpl
));
1233 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1234 return E_OUTOFMEMORY
;
1237 object
->lpVtbl
= &IWineD3DPalette_Vtbl
;
1239 object
->Flags
= Flags
;
1240 object
->parent
= Parent
;
1241 object
->device
= This
;
1242 object
->palNumEntries
= IWineD3DPaletteImpl_Size(Flags
);
1243 object
->hpal
= CreatePalette((const LOGPALETTE
*)&(object
->palVersion
));
1246 HeapFree( GetProcessHeap(), 0, object
);
1247 return E_OUTOFMEMORY
;
1250 hr
= IWineD3DPalette_SetEntries((IWineD3DPalette
*) object
, 0, 0, IWineD3DPaletteImpl_Size(Flags
), PalEnt
);
1252 IWineD3DPalette_Release((IWineD3DPalette
*) object
);
1256 *Palette
= (IWineD3DPalette
*) object
;
1261 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl
*This
, const char *filename
) {
1265 HDC dcb
= NULL
, dcs
= NULL
;
1266 WINEDDCOLORKEY colorkey
;
1268 hbm
= LoadImageA(NULL
, filename
, IMAGE_BITMAP
, 0, 0, LR_LOADFROMFILE
| LR_CREATEDIBSECTION
);
1271 GetObjectA(hbm
, sizeof(BITMAP
), &bm
);
1272 dcb
= CreateCompatibleDC(NULL
);
1274 SelectObject(dcb
, hbm
);
1278 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1279 * couldn't be loaded
1281 memset(&bm
, 0, sizeof(bm
));
1286 hr
= IWineD3DDevice_CreateSurface((IWineD3DDevice
*)This
, bm
.bmWidth
, bm
.bmHeight
, WINED3DFMT_B5G6R5_UNORM
, TRUE
,
1287 FALSE
, 0, &This
->logo_surface
, 0, WINED3DPOOL_DEFAULT
, WINED3DMULTISAMPLE_NONE
, 0, SURFACE_OPENGL
,
1288 NULL
, &wined3d_null_parent_ops
);
1290 ERR("Wine logo requested, but failed to create surface\n");
1295 hr
= IWineD3DSurface_GetDC(This
->logo_surface
, &dcs
);
1296 if(FAILED(hr
)) goto out
;
1297 BitBlt(dcs
, 0, 0, bm
.bmWidth
, bm
.bmHeight
, dcb
, 0, 0, SRCCOPY
);
1298 IWineD3DSurface_ReleaseDC(This
->logo_surface
, dcs
);
1300 colorkey
.dwColorSpaceLowValue
= 0;
1301 colorkey
.dwColorSpaceHighValue
= 0;
1302 IWineD3DSurface_SetColorKey(This
->logo_surface
, WINEDDCKEY_SRCBLT
, &colorkey
);
1304 /* Fill the surface with a white color to show that wined3d is there */
1305 IWineD3DDevice_ColorFill((IWineD3DDevice
*) This
, This
->logo_surface
, NULL
, 0xffffffff);
1309 if (dcb
) DeleteDC(dcb
);
1310 if (hbm
) DeleteObject(hbm
);
1313 /* Context activation is done by the caller. */
1314 static void create_dummy_textures(IWineD3DDeviceImpl
*This
)
1316 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
1318 /* Under DirectX you can have texture stage operations even if no texture is
1319 bound, whereas opengl will only do texture operations when a valid texture is
1320 bound. We emulate this by creating dummy textures and binding them to each
1321 texture stage, but disable all stages by default. Hence if a stage is enabled
1322 then the default texture will kick in until replaced by a SetTexture call */
1325 if (gl_info
->supported
[APPLE_CLIENT_STORAGE
])
1327 /* The dummy texture does not have client storage backing */
1328 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
1329 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1332 for (i
= 0; i
< gl_info
->limits
.textures
; ++i
)
1334 GLubyte white
= 255;
1336 /* Make appropriate texture active */
1337 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
+ i
));
1338 checkGLcall("glActiveTextureARB");
1340 /* Generate an opengl texture name */
1341 glGenTextures(1, &This
->dummyTextureName
[i
]);
1342 checkGLcall("glGenTextures");
1343 TRACE("Dummy Texture %d given name %d\n", i
, This
->dummyTextureName
[i
]);
1345 /* Generate a dummy 2d texture (not using 1d because they cause many
1346 * DRI drivers fall back to sw) */
1347 glBindTexture(GL_TEXTURE_2D
, This
->dummyTextureName
[i
]);
1348 checkGLcall("glBindTexture");
1350 glTexImage2D(GL_TEXTURE_2D
, 0, GL_LUMINANCE
, 1, 1, 0, GL_LUMINANCE
, GL_UNSIGNED_BYTE
, &white
);
1351 checkGLcall("glTexImage2D");
1354 if (gl_info
->supported
[APPLE_CLIENT_STORAGE
])
1356 /* Reenable because if supported it is enabled by default */
1357 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
1358 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1364 /* Context activation is done by the caller. */
1365 static void destroy_dummy_textures(IWineD3DDeviceImpl
*device
, const struct wined3d_gl_info
*gl_info
)
1368 glDeleteTextures(gl_info
->limits
.textures
, device
->dummyTextureName
);
1369 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1372 memset(device
->dummyTextureName
, 0, gl_info
->limits
.textures
* sizeof(*device
->dummyTextureName
));
1375 static HRESULT WINAPI
IWineD3DDeviceImpl_Init3D(IWineD3DDevice
*iface
,
1376 WINED3DPRESENT_PARAMETERS
*pPresentationParameters
)
1378 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1379 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
1380 IWineD3DSwapChainImpl
*swapchain
= NULL
;
1381 struct wined3d_context
*context
;
1386 TRACE("(%p)->(%p)\n", This
, pPresentationParameters
);
1388 if(This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
1389 if(!This
->adapter
->opengl
) return WINED3DERR_INVALIDCALL
;
1391 if (!pPresentationParameters
->Windowed
)
1393 This
->focus_window
= This
->createParms
.hFocusWindow
;
1394 if (!This
->focus_window
) This
->focus_window
= pPresentationParameters
->hDeviceWindow
;
1395 if (!wined3d_register_window(This
->focus_window
, This
))
1397 ERR("Failed to register window %p.\n", This
->focus_window
);
1402 TRACE("(%p) : Creating stateblock\n", This
);
1403 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1404 hr
= IWineD3DDevice_CreateStateBlock(iface
,
1406 (IWineD3DStateBlock
**)&This
->stateBlock
,
1408 if (WINED3D_OK
!= hr
) { /* Note: No parent needed for initial internal stateblock */
1409 WARN("Failed to create stateblock\n");
1412 TRACE("(%p) : Created stateblock (%p)\n", This
, This
->stateBlock
);
1413 This
->updateStateBlock
= This
->stateBlock
;
1414 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
1416 This
->render_targets
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
1417 sizeof(IWineD3DSurface
*) * gl_info
->limits
.buffers
);
1418 This
->draw_buffers
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
1419 sizeof(GLenum
) * gl_info
->limits
.buffers
);
1421 This
->NumberOfPalettes
= 1;
1422 This
->palettes
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(PALETTEENTRY
*));
1423 if(!This
->palettes
|| !This
->render_targets
|| !This
->draw_buffers
) {
1424 ERR("Out of memory!\n");
1428 This
->palettes
[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY
) * 256);
1429 if(!This
->palettes
[0]) {
1430 ERR("Out of memory!\n");
1434 for (i
= 0; i
< 256; ++i
) {
1435 This
->palettes
[0][i
].peRed
= 0xFF;
1436 This
->palettes
[0][i
].peGreen
= 0xFF;
1437 This
->palettes
[0][i
].peBlue
= 0xFF;
1438 This
->palettes
[0][i
].peFlags
= 0xFF;
1440 This
->currentPalette
= 0;
1442 /* Initialize the texture unit mapping to a 1:1 mapping */
1443 for (state
= 0; state
< MAX_COMBINED_SAMPLERS
; ++state
)
1445 if (state
< gl_info
->limits
.fragment_samplers
)
1447 This
->texUnitMap
[state
] = state
;
1448 This
->rev_tex_unit_map
[state
] = state
;
1450 This
->texUnitMap
[state
] = WINED3D_UNMAPPED_STAGE
;
1451 This
->rev_tex_unit_map
[state
] = WINED3D_UNMAPPED_STAGE
;
1455 if (This
->focus_window
) SetFocus(This
->focus_window
);
1457 /* Setup the implicit swapchain. This also initializes a context. */
1458 TRACE("Creating implicit swapchain\n");
1459 hr
= IWineD3DDeviceParent_CreateSwapChain(This
->device_parent
,
1460 pPresentationParameters
, (IWineD3DSwapChain
**)&swapchain
);
1463 WARN("Failed to create implicit swapchain\n");
1467 This
->NumberOfSwapChains
= 1;
1468 This
->swapchains
= HeapAlloc(GetProcessHeap(), 0, This
->NumberOfSwapChains
* sizeof(IWineD3DSwapChain
*));
1469 if(!This
->swapchains
) {
1470 ERR("Out of memory!\n");
1473 This
->swapchains
[0] = (IWineD3DSwapChain
*) swapchain
;
1475 if(swapchain
->backBuffer
&& swapchain
->backBuffer
[0]) {
1476 TRACE("Setting rendertarget to %p\n", swapchain
->backBuffer
);
1477 This
->render_targets
[0] = swapchain
->backBuffer
[0];
1480 TRACE("Setting rendertarget to %p\n", swapchain
->frontBuffer
);
1481 This
->render_targets
[0] = swapchain
->frontBuffer
;
1483 IWineD3DSurface_AddRef(This
->render_targets
[0]);
1485 /* Depth Stencil support */
1486 This
->stencilBufferTarget
= This
->auto_depth_stencil_buffer
;
1487 if (NULL
!= This
->stencilBufferTarget
) {
1488 IWineD3DSurface_AddRef(This
->stencilBufferTarget
);
1491 hr
= This
->shader_backend
->shader_alloc_private(iface
);
1493 TRACE("Shader private data couldn't be allocated\n");
1496 hr
= This
->frag_pipe
->alloc_private(iface
);
1498 TRACE("Fragment pipeline private data couldn't be allocated\n");
1501 hr
= This
->blitter
->alloc_private(iface
);
1503 TRACE("Blitter private data couldn't be allocated\n");
1507 /* Set up some starting GL setup */
1509 /* Setup all the devices defaults */
1510 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock
*)This
->stateBlock
);
1512 context
= context_acquire(This
, swapchain
->frontBuffer
, CTXUSAGE_RESOURCELOAD
);
1514 create_dummy_textures(This
);
1518 /* Initialize the current view state */
1519 This
->view_ident
= 1;
1520 This
->contexts
[0]->last_was_rhw
= 0;
1521 glGetIntegerv(GL_MAX_LIGHTS
, &This
->maxConcurrentLights
);
1522 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1524 switch(wined3d_settings
.offscreen_rendering_mode
) {
1526 This
->offscreenBuffer
= GL_COLOR_ATTACHMENT0
;
1530 This
->offscreenBuffer
= GL_BACK
;
1533 case ORM_BACKBUFFER
:
1535 if (context_get_current()->aux_buffers
> 0)
1537 TRACE("Using auxilliary buffer for offscreen rendering\n");
1538 This
->offscreenBuffer
= GL_AUX0
;
1540 TRACE("Using back buffer for offscreen rendering\n");
1541 This
->offscreenBuffer
= GL_BACK
;
1546 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This
, This
);
1549 context_release(context
);
1551 /* Clear the screen */
1552 IWineD3DDevice_Clear((IWineD3DDevice
*) This
, 0, NULL
,
1553 WINED3DCLEAR_TARGET
| pPresentationParameters
->EnableAutoDepthStencil
? WINED3DCLEAR_ZBUFFER
| WINED3DCLEAR_STENCIL
: 0,
1556 This
->d3d_initialized
= TRUE
;
1558 if(wined3d_settings
.logo
) {
1559 IWineD3DDeviceImpl_LoadLogo(This
, wined3d_settings
.logo
);
1561 This
->highest_dirty_ps_const
= 0;
1562 This
->highest_dirty_vs_const
= 0;
1566 HeapFree(GetProcessHeap(), 0, This
->render_targets
);
1567 HeapFree(GetProcessHeap(), 0, This
->draw_buffers
);
1568 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
1569 This
->NumberOfSwapChains
= 0;
1570 if(This
->palettes
) {
1571 HeapFree(GetProcessHeap(), 0, This
->palettes
[0]);
1572 HeapFree(GetProcessHeap(), 0, This
->palettes
);
1574 This
->NumberOfPalettes
= 0;
1576 IWineD3DSwapChain_Release( (IWineD3DSwapChain
*) swapchain
);
1578 if(This
->stateBlock
) {
1579 IWineD3DStateBlock_Release((IWineD3DStateBlock
*) This
->stateBlock
);
1580 This
->stateBlock
= NULL
;
1582 if (This
->blit_priv
) {
1583 This
->blitter
->free_private(iface
);
1585 if (This
->fragment_priv
) {
1586 This
->frag_pipe
->free_private(iface
);
1588 if (This
->shader_priv
) {
1589 This
->shader_backend
->shader_free_private(iface
);
1591 if (This
->focus_window
) wined3d_unregister_window(This
->focus_window
);
1595 static HRESULT WINAPI
IWineD3DDeviceImpl_InitGDI(IWineD3DDevice
*iface
,
1596 WINED3DPRESENT_PARAMETERS
*pPresentationParameters
)
1598 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1599 IWineD3DSwapChainImpl
*swapchain
= NULL
;
1602 /* Setup the implicit swapchain */
1603 TRACE("Creating implicit swapchain\n");
1604 hr
= IWineD3DDeviceParent_CreateSwapChain(This
->device_parent
,
1605 pPresentationParameters
, (IWineD3DSwapChain
**)&swapchain
);
1608 WARN("Failed to create implicit swapchain\n");
1612 This
->NumberOfSwapChains
= 1;
1613 This
->swapchains
= HeapAlloc(GetProcessHeap(), 0, This
->NumberOfSwapChains
* sizeof(IWineD3DSwapChain
*));
1614 if(!This
->swapchains
) {
1615 ERR("Out of memory!\n");
1618 This
->swapchains
[0] = (IWineD3DSwapChain
*) swapchain
;
1622 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
1626 static HRESULT WINAPI
device_unload_resource(IWineD3DResource
*resource
, void *ctx
)
1628 IWineD3DResource_UnLoad(resource
);
1629 IWineD3DResource_Release(resource
);
1633 static HRESULT WINAPI
IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice
*iface
,
1634 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain
)
1636 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1637 const struct wined3d_gl_info
*gl_info
;
1638 struct wined3d_context
*context
;
1641 TRACE("(%p)\n", This
);
1643 if(!This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
1645 /* I don't think that the interface guarantees that the device is destroyed from the same thread
1646 * it was created. Thus make sure a context is active for the glDelete* calls
1648 context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
1649 gl_info
= context
->gl_info
;
1651 if(This
->logo_surface
) IWineD3DSurface_Release(This
->logo_surface
);
1653 /* Unload resources */
1654 IWineD3DDevice_EnumResources(iface
, device_unload_resource
, NULL
);
1656 TRACE("Deleting high order patches\n");
1657 for(i
= 0; i
< PATCHMAP_SIZE
; i
++) {
1658 struct list
*e1
, *e2
;
1659 struct WineD3DRectPatch
*patch
;
1660 LIST_FOR_EACH_SAFE(e1
, e2
, &This
->patches
[i
]) {
1661 patch
= LIST_ENTRY(e1
, struct WineD3DRectPatch
, entry
);
1662 IWineD3DDevice_DeletePatch(iface
, patch
->Handle
);
1666 /* Delete the palette conversion shader if it is around */
1667 if(This
->paletteConversionShader
) {
1669 GL_EXTCALL(glDeleteProgramsARB(1, &This
->paletteConversionShader
));
1671 This
->paletteConversionShader
= 0;
1674 /* Delete the pbuffer context if there is any */
1675 if(This
->pbufferContext
) context_destroy(This
, This
->pbufferContext
);
1677 /* Delete the mouse cursor texture */
1678 if(This
->cursorTexture
) {
1680 glDeleteTextures(1, &This
->cursorTexture
);
1682 This
->cursorTexture
= 0;
1685 for (sampler
= 0; sampler
< MAX_FRAGMENT_SAMPLERS
; ++sampler
) {
1686 IWineD3DDevice_SetTexture(iface
, sampler
, NULL
);
1688 for (sampler
= 0; sampler
< MAX_VERTEX_SAMPLERS
; ++sampler
) {
1689 IWineD3DDevice_SetTexture(iface
, WINED3DVERTEXTEXTURESAMPLER0
+ sampler
, NULL
);
1692 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
1693 * private data, it might contain opengl pointers
1695 if(This
->depth_blt_texture
) {
1697 glDeleteTextures(1, &This
->depth_blt_texture
);
1699 This
->depth_blt_texture
= 0;
1701 if (This
->depth_blt_rb
) {
1703 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &This
->depth_blt_rb
);
1705 This
->depth_blt_rb
= 0;
1706 This
->depth_blt_rb_w
= 0;
1707 This
->depth_blt_rb_h
= 0;
1710 /* Release the update stateblock */
1711 if(IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
) > 0){
1712 if(This
->updateStateBlock
!= This
->stateBlock
)
1713 FIXME("(%p) Something's still holding the Update stateblock\n",This
);
1715 This
->updateStateBlock
= NULL
;
1717 { /* because were not doing proper internal refcounts releasing the primary state block
1718 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1719 to set this->stateBlock = NULL; first */
1720 IWineD3DStateBlock
*stateBlock
= (IWineD3DStateBlock
*)This
->stateBlock
;
1721 This
->stateBlock
= NULL
;
1723 /* Release the stateblock */
1724 if(IWineD3DStateBlock_Release(stateBlock
) > 0){
1725 FIXME("(%p) Something's still holding the Update stateblock\n",This
);
1729 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
1730 This
->blitter
->free_private(iface
);
1731 This
->frag_pipe
->free_private(iface
);
1732 This
->shader_backend
->shader_free_private(iface
);
1734 /* Release the buffers (with sanity checks)*/
1735 TRACE("Releasing the depth stencil buffer at %p\n", This
->stencilBufferTarget
);
1736 if(This
->stencilBufferTarget
!= NULL
&& (IWineD3DSurface_Release(This
->stencilBufferTarget
) >0)){
1737 if(This
->auto_depth_stencil_buffer
!= This
->stencilBufferTarget
)
1738 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This
);
1740 This
->stencilBufferTarget
= NULL
;
1742 TRACE("Releasing the render target at %p\n", This
->render_targets
[0]);
1743 if(IWineD3DSurface_Release(This
->render_targets
[0]) >0){
1744 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1746 TRACE("Setting rendertarget to NULL\n");
1747 This
->render_targets
[0] = NULL
;
1749 if (This
->auto_depth_stencil_buffer
) {
1750 if (IWineD3DSurface_Release(This
->auto_depth_stencil_buffer
) > 0)
1752 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This
);
1754 This
->auto_depth_stencil_buffer
= NULL
;
1757 context_release(context
);
1759 for(i
=0; i
< This
->NumberOfSwapChains
; i
++) {
1760 TRACE("Releasing the implicit swapchain %d\n", i
);
1761 if (D3DCB_DestroySwapChain(This
->swapchains
[i
]) > 0) {
1762 FIXME("(%p) Something's still holding the implicit swapchain\n", This
);
1766 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
1767 This
->swapchains
= NULL
;
1768 This
->NumberOfSwapChains
= 0;
1770 for (i
= 0; i
< This
->NumberOfPalettes
; i
++) HeapFree(GetProcessHeap(), 0, This
->palettes
[i
]);
1771 HeapFree(GetProcessHeap(), 0, This
->palettes
);
1772 This
->palettes
= NULL
;
1773 This
->NumberOfPalettes
= 0;
1775 HeapFree(GetProcessHeap(), 0, This
->render_targets
);
1776 HeapFree(GetProcessHeap(), 0, This
->draw_buffers
);
1777 This
->render_targets
= NULL
;
1778 This
->draw_buffers
= NULL
;
1780 This
->d3d_initialized
= FALSE
;
1782 if (This
->focus_window
) wined3d_unregister_window(This
->focus_window
);
1787 static HRESULT WINAPI
IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice
*iface
, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain
) {
1788 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1791 for(i
=0; i
< This
->NumberOfSwapChains
; i
++) {
1792 TRACE("Releasing the implicit swapchain %d\n", i
);
1793 if (D3DCB_DestroySwapChain(This
->swapchains
[i
]) > 0) {
1794 FIXME("(%p) Something's still holding the implicit swapchain\n", This
);
1798 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
1799 This
->swapchains
= NULL
;
1800 This
->NumberOfSwapChains
= 0;
1804 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
1805 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
1806 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
1808 * There is no way to deactivate thread safety once it is enabled.
1810 static void WINAPI
IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice
*iface
) {
1811 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1813 /*For now just store the flag(needed in case of ddraw) */
1814 This
->createParms
.BehaviorFlags
|= WINED3DCREATE_MULTITHREADED
;
1817 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
,
1818 const WINED3DDISPLAYMODE
* pMode
) {
1820 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1822 const struct GlPixelFormatDesc
*format_desc
= getFormatDescEntry(pMode
->Format
, &This
->adapter
->gl_info
);
1825 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This
, iSwapChain
, pMode
, pMode
->Width
, pMode
->Height
, pMode
->RefreshRate
, debug_d3dformat(pMode
->Format
));
1827 /* Resize the screen even without a window:
1828 * The app could have unset it with SetCooperativeLevel, but not called
1829 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1830 * but we don't have any hwnd
1833 memset(&devmode
, 0, sizeof(devmode
));
1834 devmode
.dmSize
= sizeof(devmode
);
1835 devmode
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
1836 devmode
.dmBitsPerPel
= format_desc
->byte_count
* 8;
1837 devmode
.dmPelsWidth
= pMode
->Width
;
1838 devmode
.dmPelsHeight
= pMode
->Height
;
1840 devmode
.dmDisplayFrequency
= pMode
->RefreshRate
;
1841 if (pMode
->RefreshRate
!= 0) {
1842 devmode
.dmFields
|= DM_DISPLAYFREQUENCY
;
1845 /* Only change the mode if necessary */
1846 if( (This
->ddraw_width
== pMode
->Width
) &&
1847 (This
->ddraw_height
== pMode
->Height
) &&
1848 (This
->ddraw_format
== pMode
->Format
) &&
1849 (pMode
->RefreshRate
== 0) ) {
1853 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
);
1854 if (ret
!= DISP_CHANGE_SUCCESSFUL
) {
1855 if(devmode
.dmDisplayFrequency
!= 0) {
1856 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1857 devmode
.dmFields
&= ~DM_DISPLAYFREQUENCY
;
1858 devmode
.dmDisplayFrequency
= 0;
1859 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
) != DISP_CHANGE_SUCCESSFUL
;
1861 if(ret
!= DISP_CHANGE_SUCCESSFUL
) {
1862 return WINED3DERR_NOTAVAILABLE
;
1866 /* Store the new values */
1867 This
->ddraw_width
= pMode
->Width
;
1868 This
->ddraw_height
= pMode
->Height
;
1869 This
->ddraw_format
= pMode
->Format
;
1871 /* And finally clip mouse to our screen */
1872 SetRect(&clip_rc
, 0, 0, pMode
->Width
, pMode
->Height
);
1873 ClipCursor(&clip_rc
);
1878 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice
*iface
, IWineD3D
**ppD3D
) {
1879 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1880 *ppD3D
= This
->wined3d
;
1881 TRACE("Returning %p.\n", *ppD3D
);
1882 IWineD3D_AddRef(*ppD3D
);
1886 static UINT WINAPI
IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice
*iface
) {
1887 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1889 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This
,
1890 (This
->adapter
->TextureRam
/(1024*1024)),
1891 ((This
->adapter
->TextureRam
- This
->adapter
->UsedTextureRam
) / (1024*1024)));
1892 /* return simulated texture memory left */
1893 return (This
->adapter
->TextureRam
- This
->adapter
->UsedTextureRam
);
1897 * Get / Set Stream Source
1899 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice
*iface
, UINT StreamNumber
,
1900 IWineD3DBuffer
*pStreamData
, UINT OffsetInBytes
, UINT Stride
)
1902 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1903 IWineD3DBuffer
*oldSrc
;
1905 if (StreamNumber
>= MAX_STREAMS
) {
1906 WARN("Stream out of range %d\n", StreamNumber
);
1907 return WINED3DERR_INVALIDCALL
;
1908 } else if(OffsetInBytes
& 0x3) {
1909 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes
);
1910 return WINED3DERR_INVALIDCALL
;
1913 oldSrc
= This
->updateStateBlock
->streamSource
[StreamNumber
];
1914 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This
, StreamNumber
, oldSrc
, pStreamData
, OffsetInBytes
, Stride
);
1916 This
->updateStateBlock
->changed
.streamSource
|= 1 << StreamNumber
;
1918 if(oldSrc
== pStreamData
&&
1919 This
->updateStateBlock
->streamStride
[StreamNumber
] == Stride
&&
1920 This
->updateStateBlock
->streamOffset
[StreamNumber
] == OffsetInBytes
) {
1921 TRACE("Application is setting the old values over, nothing to do\n");
1925 This
->updateStateBlock
->streamSource
[StreamNumber
] = pStreamData
;
1927 This
->updateStateBlock
->streamStride
[StreamNumber
] = Stride
;
1928 This
->updateStateBlock
->streamOffset
[StreamNumber
] = OffsetInBytes
;
1931 /* Handle recording of state blocks */
1932 if (This
->isRecordingState
) {
1933 TRACE("Recording... not performing anything\n");
1934 if (pStreamData
) IWineD3DBuffer_AddRef(pStreamData
);
1935 if (oldSrc
) IWineD3DBuffer_Release(oldSrc
);
1939 if (pStreamData
!= NULL
) {
1940 InterlockedIncrement(&((struct wined3d_buffer
*)pStreamData
)->bind_count
);
1941 IWineD3DBuffer_AddRef(pStreamData
);
1943 if (oldSrc
!= NULL
) {
1944 InterlockedDecrement(&((struct wined3d_buffer
*)oldSrc
)->bind_count
);
1945 IWineD3DBuffer_Release(oldSrc
);
1948 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
1953 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice
*iface
,
1954 UINT StreamNumber
, IWineD3DBuffer
**pStream
, UINT
*pOffset
, UINT
*pStride
)
1956 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1958 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This
, StreamNumber
,
1959 This
->stateBlock
->streamSource
[StreamNumber
],
1960 This
->stateBlock
->streamOffset
[StreamNumber
],
1961 This
->stateBlock
->streamStride
[StreamNumber
]);
1963 if (StreamNumber
>= MAX_STREAMS
) {
1964 WARN("Stream out of range %d\n", StreamNumber
);
1965 return WINED3DERR_INVALIDCALL
;
1967 *pStream
= This
->stateBlock
->streamSource
[StreamNumber
];
1968 *pStride
= This
->stateBlock
->streamStride
[StreamNumber
];
1970 *pOffset
= This
->stateBlock
->streamOffset
[StreamNumber
];
1973 if (*pStream
!= NULL
) {
1974 IWineD3DBuffer_AddRef(*pStream
); /* We have created a new reference to the VB */
1979 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT Divider
) {
1980 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1981 UINT oldFlags
= This
->updateStateBlock
->streamFlags
[StreamNumber
];
1982 UINT oldFreq
= This
->updateStateBlock
->streamFreq
[StreamNumber
];
1984 /* Verify input at least in d3d9 this is invalid*/
1985 if( (Divider
& WINED3DSTREAMSOURCE_INSTANCEDATA
) && (Divider
& WINED3DSTREAMSOURCE_INDEXEDDATA
)){
1986 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
1987 return WINED3DERR_INVALIDCALL
;
1989 if( (Divider
& WINED3DSTREAMSOURCE_INSTANCEDATA
) && StreamNumber
== 0 ){
1990 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
1991 return WINED3DERR_INVALIDCALL
;
1994 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
1995 return WINED3DERR_INVALIDCALL
;
1998 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This
, StreamNumber
, Divider
);
1999 This
->updateStateBlock
->streamFlags
[StreamNumber
] = Divider
& (WINED3DSTREAMSOURCE_INSTANCEDATA
| WINED3DSTREAMSOURCE_INDEXEDDATA
);
2001 This
->updateStateBlock
->changed
.streamFreq
|= 1 << StreamNumber
;
2002 This
->updateStateBlock
->streamFreq
[StreamNumber
] = Divider
& 0x7FFFFF;
2004 if(This
->updateStateBlock
->streamFreq
[StreamNumber
] != oldFreq
||
2005 This
->updateStateBlock
->streamFlags
[StreamNumber
] != oldFlags
) {
2006 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2012 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT
* Divider
) {
2013 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2015 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This
, StreamNumber
, Divider
);
2016 *Divider
= This
->updateStateBlock
->streamFreq
[StreamNumber
] | This
->updateStateBlock
->streamFlags
[StreamNumber
];
2018 TRACE("(%p) : returning %d\n", This
, *Divider
);
2024 * Get / Set & Multiply Transform
2026 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE d3dts
, CONST WINED3DMATRIX
* lpmatrix
) {
2027 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2029 /* Most of this routine, comments included copied from ddraw tree initially: */
2030 TRACE("(%p) : Transform State=%s\n", This
, debug_d3dtstype(d3dts
));
2032 /* Handle recording of state blocks */
2033 if (This
->isRecordingState
) {
2034 TRACE("Recording... not performing anything\n");
2035 This
->updateStateBlock
->changed
.transform
[d3dts
>> 5] |= 1 << (d3dts
& 0x1f);
2036 This
->updateStateBlock
->transforms
[d3dts
] = *lpmatrix
;
2041 * If the new matrix is the same as the current one,
2042 * we cut off any further processing. this seems to be a reasonable
2043 * optimization because as was noticed, some apps (warcraft3 for example)
2044 * tend towards setting the same matrix repeatedly for some reason.
2046 * From here on we assume that the new matrix is different, wherever it matters.
2048 if (!memcmp(&This
->stateBlock
->transforms
[d3dts
].u
.m
[0][0], lpmatrix
, sizeof(WINED3DMATRIX
))) {
2049 TRACE("The app is setting the same matrix over again\n");
2052 conv_mat(lpmatrix
, &This
->stateBlock
->transforms
[d3dts
].u
.m
[0][0]);
2056 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2057 where ViewMat = Camera space, WorldMat = world space.
2059 In OpenGL, camera and world space is combined into GL_MODELVIEW
2060 matrix. The Projection matrix stay projection matrix.
2063 /* Capture the times we can just ignore the change for now */
2064 if (d3dts
== WINED3DTS_VIEW
) { /* handle the VIEW matrix */
2065 This
->view_ident
= !memcmp(lpmatrix
, identity
, 16 * sizeof(float));
2066 /* Handled by the state manager */
2069 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TRANSFORM(d3dts
));
2073 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, WINED3DMATRIX
* pMatrix
) {
2074 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2075 TRACE("(%p) : for Transform State %s\n", This
, debug_d3dtstype(State
));
2076 *pMatrix
= This
->stateBlock
->transforms
[State
];
2080 static HRESULT WINAPI
IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, CONST WINED3DMATRIX
* pMatrix
) {
2081 const WINED3DMATRIX
*mat
= NULL
;
2084 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2085 * below means it will be recorded in a state block change, but it
2086 * works regardless where it is recorded.
2087 * If this is found to be wrong, change to StateBlock.
2089 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2090 TRACE("(%p) : For state %s\n", This
, debug_d3dtstype(State
));
2092 if (State
<= HIGHEST_TRANSFORMSTATE
)
2094 mat
= &This
->updateStateBlock
->transforms
[State
];
2096 FIXME("Unhandled transform state!!\n");
2099 multiply_matrix(&temp
, mat
, pMatrix
);
2101 /* Apply change via set transform - will reapply to eg. lights this way */
2102 return IWineD3DDeviceImpl_SetTransform(iface
, State
, &temp
);
2108 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2109 you can reference any indexes you want as long as that number max are enabled at any
2110 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2111 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2112 but when recording, just build a chain pretty much of commands to be replayed. */
2114 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLight(IWineD3DDevice
*iface
, DWORD Index
, CONST WINED3DLIGHT
* pLight
) {
2116 struct wined3d_light_info
*object
= NULL
;
2117 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2120 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2121 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This
, Index
, pLight
, Hi
);
2123 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2127 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2128 return WINED3DERR_INVALIDCALL
;
2131 switch(pLight
->Type
) {
2132 case WINED3DLIGHT_POINT
:
2133 case WINED3DLIGHT_SPOT
:
2134 case WINED3DLIGHT_PARALLELPOINT
:
2135 case WINED3DLIGHT_GLSPOT
:
2136 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2139 if (pLight
->Attenuation0
< 0.0f
|| pLight
->Attenuation1
< 0.0f
|| pLight
->Attenuation2
< 0.0f
)
2141 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2142 return WINED3DERR_INVALIDCALL
;
2146 case WINED3DLIGHT_DIRECTIONAL
:
2147 /* Ignores attenuation */
2151 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2152 return WINED3DERR_INVALIDCALL
;
2155 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
])
2157 object
= LIST_ENTRY(e
, struct wined3d_light_info
, entry
);
2158 if(object
->OriginalIndex
== Index
) break;
2163 TRACE("Adding new light\n");
2164 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
2166 ERR("Out of memory error when allocating a light\n");
2167 return E_OUTOFMEMORY
;
2169 list_add_head(&This
->updateStateBlock
->lightMap
[Hi
], &object
->entry
);
2170 object
->glIndex
= -1;
2171 object
->OriginalIndex
= Index
;
2174 /* Initialize the object */
2175 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
,
2176 pLight
->Diffuse
.r
, pLight
->Diffuse
.g
, pLight
->Diffuse
.b
, pLight
->Diffuse
.a
,
2177 pLight
->Specular
.r
, pLight
->Specular
.g
, pLight
->Specular
.b
, pLight
->Specular
.a
,
2178 pLight
->Ambient
.r
, pLight
->Ambient
.g
, pLight
->Ambient
.b
, pLight
->Ambient
.a
);
2179 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight
->Position
.x
, pLight
->Position
.y
, pLight
->Position
.z
,
2180 pLight
->Direction
.x
, pLight
->Direction
.y
, pLight
->Direction
.z
);
2181 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight
->Range
, pLight
->Falloff
, pLight
->Theta
, pLight
->Phi
);
2183 /* Save away the information */
2184 object
->OriginalParms
= *pLight
;
2186 switch (pLight
->Type
) {
2187 case WINED3DLIGHT_POINT
:
2189 object
->lightPosn
[0] = pLight
->Position
.x
;
2190 object
->lightPosn
[1] = pLight
->Position
.y
;
2191 object
->lightPosn
[2] = pLight
->Position
.z
;
2192 object
->lightPosn
[3] = 1.0f
;
2193 object
->cutoff
= 180.0f
;
2197 case WINED3DLIGHT_DIRECTIONAL
:
2199 object
->lightPosn
[0] = -pLight
->Direction
.x
;
2200 object
->lightPosn
[1] = -pLight
->Direction
.y
;
2201 object
->lightPosn
[2] = -pLight
->Direction
.z
;
2202 object
->lightPosn
[3] = 0.0f
;
2203 object
->exponent
= 0.0f
;
2204 object
->cutoff
= 180.0f
;
2207 case WINED3DLIGHT_SPOT
:
2209 object
->lightPosn
[0] = pLight
->Position
.x
;
2210 object
->lightPosn
[1] = pLight
->Position
.y
;
2211 object
->lightPosn
[2] = pLight
->Position
.z
;
2212 object
->lightPosn
[3] = 1.0f
;
2215 object
->lightDirn
[0] = pLight
->Direction
.x
;
2216 object
->lightDirn
[1] = pLight
->Direction
.y
;
2217 object
->lightDirn
[2] = pLight
->Direction
.z
;
2218 object
->lightDirn
[3] = 1.0f
;
2221 * opengl-ish and d3d-ish spot lights use too different models for the
2222 * light "intensity" as a function of the angle towards the main light direction,
2223 * so we only can approximate very roughly.
2224 * however spot lights are rather rarely used in games (if ever used at all).
2225 * furthermore if still used, probably nobody pays attention to such details.
2227 if (pLight
->Falloff
== 0) {
2228 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2229 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2230 * will always be 1.0 for both of them, and we don't have to care for the
2231 * rest of the rather complex calculation
2233 object
->exponent
= 0.0f
;
2235 rho
= pLight
->Theta
+ (pLight
->Phi
- pLight
->Theta
)/(2*pLight
->Falloff
);
2236 if (rho
< 0.0001f
) rho
= 0.0001f
;
2237 object
->exponent
= -0.3f
/logf(cosf(rho
/2));
2239 if (object
->exponent
> 128.0f
)
2241 object
->exponent
= 128.0f
;
2243 object
->cutoff
= pLight
->Phi
*90/M_PI
;
2249 FIXME("Unrecognized light type %d\n", pLight
->Type
);
2252 /* Update the live definitions if the light is currently assigned a glIndex */
2253 if (object
->glIndex
!= -1 && !This
->isRecordingState
) {
2254 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(object
->glIndex
));
2259 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLight(IWineD3DDevice
*iface
, DWORD Index
, WINED3DLIGHT
*pLight
)
2261 struct wined3d_light_info
*lightInfo
= NULL
;
2262 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2263 DWORD Hi
= LIGHTMAP_HASHFUNC(Index
);
2265 TRACE("(%p) : Idx(%d), pLight(%p)\n", This
, Index
, pLight
);
2267 LIST_FOR_EACH(e
, &This
->stateBlock
->lightMap
[Hi
])
2269 lightInfo
= LIST_ENTRY(e
, struct wined3d_light_info
, entry
);
2270 if(lightInfo
->OriginalIndex
== Index
) break;
2274 if (lightInfo
== NULL
) {
2275 TRACE("Light information requested but light not defined\n");
2276 return WINED3DERR_INVALIDCALL
;
2279 *pLight
= lightInfo
->OriginalParms
;
2284 * Get / Set Light Enable
2285 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2287 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice
*iface
, DWORD Index
, BOOL Enable
)
2289 struct wined3d_light_info
*lightInfo
= NULL
;
2290 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2291 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2293 TRACE("(%p) : Idx(%d), enable? %d\n", This
, Index
, Enable
);
2295 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
])
2297 lightInfo
= LIST_ENTRY(e
, struct wined3d_light_info
, entry
);
2298 if(lightInfo
->OriginalIndex
== Index
) break;
2301 TRACE("Found light: %p\n", lightInfo
);
2303 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2304 if (lightInfo
== NULL
) {
2306 TRACE("Light enabled requested but light not defined, so defining one!\n");
2307 IWineD3DDeviceImpl_SetLight(iface
, Index
, &WINED3D_default_light
);
2309 /* Search for it again! Should be fairly quick as near head of list */
2310 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
])
2312 lightInfo
= LIST_ENTRY(e
, struct wined3d_light_info
, entry
);
2313 if(lightInfo
->OriginalIndex
== Index
) break;
2316 if (lightInfo
== NULL
) {
2317 FIXME("Adding default lights has failed dismally\n");
2318 return WINED3DERR_INVALIDCALL
;
2323 if(lightInfo
->glIndex
!= -1) {
2324 if(!This
->isRecordingState
) {
2325 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(lightInfo
->glIndex
));
2328 This
->updateStateBlock
->activeLights
[lightInfo
->glIndex
] = NULL
;
2329 lightInfo
->glIndex
= -1;
2331 TRACE("Light already disabled, nothing to do\n");
2333 lightInfo
->enabled
= FALSE
;
2335 lightInfo
->enabled
= TRUE
;
2336 if (lightInfo
->glIndex
!= -1) {
2338 TRACE("Nothing to do as light was enabled\n");
2341 /* Find a free gl light */
2342 for(i
= 0; i
< This
->maxConcurrentLights
; i
++) {
2343 if(This
->updateStateBlock
->activeLights
[i
] == NULL
) {
2344 This
->updateStateBlock
->activeLights
[i
] = lightInfo
;
2345 lightInfo
->glIndex
= i
;
2349 if(lightInfo
->glIndex
== -1) {
2350 /* Our tests show that Windows returns D3D_OK in this situation, even with
2351 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2352 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2353 * as well for those lights.
2355 * TODO: Test how this affects rendering
2357 WARN("Too many concurrently active lights\n");
2361 /* i == lightInfo->glIndex */
2362 if(!This
->isRecordingState
) {
2363 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(i
));
2371 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice
*iface
, DWORD Index
,BOOL
* pEnable
)
2373 struct wined3d_light_info
*lightInfo
= NULL
;
2374 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2376 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2377 TRACE("(%p) : for idx(%d)\n", This
, Index
);
2379 LIST_FOR_EACH(e
, &This
->stateBlock
->lightMap
[Hi
])
2381 lightInfo
= LIST_ENTRY(e
, struct wined3d_light_info
, entry
);
2382 if(lightInfo
->OriginalIndex
== Index
) break;
2386 if (lightInfo
== NULL
) {
2387 TRACE("Light enabled state requested but light not defined\n");
2388 return WINED3DERR_INVALIDCALL
;
2390 /* true is 128 according to SetLightEnable */
2391 *pEnable
= lightInfo
->enabled
? 128 : 0;
2396 * Get / Set Clip Planes
2398 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, CONST
float *pPlane
) {
2399 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2400 TRACE("(%p) : for idx %d, %p\n", This
, Index
, pPlane
);
2402 /* Validate Index */
2403 if (Index
>= This
->adapter
->gl_info
.limits
.clipplanes
)
2405 TRACE("Application has requested clipplane this device doesn't support\n");
2406 return WINED3DERR_INVALIDCALL
;
2409 This
->updateStateBlock
->changed
.clipplane
|= 1 << Index
;
2411 if(This
->updateStateBlock
->clipplane
[Index
][0] == pPlane
[0] &&
2412 This
->updateStateBlock
->clipplane
[Index
][1] == pPlane
[1] &&
2413 This
->updateStateBlock
->clipplane
[Index
][2] == pPlane
[2] &&
2414 This
->updateStateBlock
->clipplane
[Index
][3] == pPlane
[3]) {
2415 TRACE("Application is setting old values over, nothing to do\n");
2419 This
->updateStateBlock
->clipplane
[Index
][0] = pPlane
[0];
2420 This
->updateStateBlock
->clipplane
[Index
][1] = pPlane
[1];
2421 This
->updateStateBlock
->clipplane
[Index
][2] = pPlane
[2];
2422 This
->updateStateBlock
->clipplane
[Index
][3] = pPlane
[3];
2424 /* Handle recording of state blocks */
2425 if (This
->isRecordingState
) {
2426 TRACE("Recording... not performing anything\n");
2430 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_CLIPPLANE(Index
));
2435 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, float *pPlane
) {
2436 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2437 TRACE("(%p) : for idx %d\n", This
, Index
);
2439 /* Validate Index */
2440 if (Index
>= This
->adapter
->gl_info
.limits
.clipplanes
)
2442 TRACE("Application has requested clipplane this device doesn't support\n");
2443 return WINED3DERR_INVALIDCALL
;
2446 pPlane
[0] = This
->stateBlock
->clipplane
[Index
][0];
2447 pPlane
[1] = This
->stateBlock
->clipplane
[Index
][1];
2448 pPlane
[2] = This
->stateBlock
->clipplane
[Index
][2];
2449 pPlane
[3] = This
->stateBlock
->clipplane
[Index
][3];
2454 * Get / Set Clip Plane Status
2455 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2457 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice
*iface
, CONST WINED3DCLIPSTATUS
* pClipStatus
) {
2458 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2459 FIXME("(%p) : stub\n", This
);
2460 if (NULL
== pClipStatus
) {
2461 return WINED3DERR_INVALIDCALL
;
2463 This
->updateStateBlock
->clip_status
.ClipUnion
= pClipStatus
->ClipUnion
;
2464 This
->updateStateBlock
->clip_status
.ClipIntersection
= pClipStatus
->ClipIntersection
;
2468 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice
*iface
, WINED3DCLIPSTATUS
* pClipStatus
) {
2469 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2470 FIXME("(%p) : stub\n", This
);
2471 if (NULL
== pClipStatus
) {
2472 return WINED3DERR_INVALIDCALL
;
2474 pClipStatus
->ClipUnion
= This
->updateStateBlock
->clip_status
.ClipUnion
;
2475 pClipStatus
->ClipIntersection
= This
->updateStateBlock
->clip_status
.ClipIntersection
;
2480 * Get / Set Material
2482 static HRESULT WINAPI
IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice
*iface
, CONST WINED3DMATERIAL
* pMaterial
) {
2483 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2485 This
->updateStateBlock
->changed
.material
= TRUE
;
2486 This
->updateStateBlock
->material
= *pMaterial
;
2488 /* Handle recording of state blocks */
2489 if (This
->isRecordingState
) {
2490 TRACE("Recording... not performing anything\n");
2494 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_MATERIAL
);
2498 static HRESULT WINAPI
IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice
*iface
, WINED3DMATERIAL
* pMaterial
) {
2499 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2500 *pMaterial
= This
->updateStateBlock
->material
;
2501 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This
, pMaterial
->Diffuse
.r
, pMaterial
->Diffuse
.g
,
2502 pMaterial
->Diffuse
.b
, pMaterial
->Diffuse
.a
);
2503 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This
, pMaterial
->Ambient
.r
, pMaterial
->Ambient
.g
,
2504 pMaterial
->Ambient
.b
, pMaterial
->Ambient
.a
);
2505 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This
, pMaterial
->Specular
.r
, pMaterial
->Specular
.g
,
2506 pMaterial
->Specular
.b
, pMaterial
->Specular
.a
);
2507 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This
, pMaterial
->Emissive
.r
, pMaterial
->Emissive
.g
,
2508 pMaterial
->Emissive
.b
, pMaterial
->Emissive
.a
);
2509 TRACE("(%p) : Power (%f)\n", This
, pMaterial
->Power
);
2517 static HRESULT WINAPI
IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice
*iface
,
2518 IWineD3DBuffer
*pIndexData
, WINED3DFORMAT fmt
)
2520 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2521 IWineD3DBuffer
*oldIdxs
;
2523 TRACE("(%p) : Setting to %p\n", This
, pIndexData
);
2524 oldIdxs
= This
->updateStateBlock
->pIndexData
;
2526 This
->updateStateBlock
->changed
.indices
= TRUE
;
2527 This
->updateStateBlock
->pIndexData
= pIndexData
;
2528 This
->updateStateBlock
->IndexFmt
= fmt
;
2530 /* Handle recording of state blocks */
2531 if (This
->isRecordingState
) {
2532 TRACE("Recording... not performing anything\n");
2533 if(pIndexData
) IWineD3DBuffer_AddRef(pIndexData
);
2534 if(oldIdxs
) IWineD3DBuffer_Release(oldIdxs
);
2538 if(oldIdxs
!= pIndexData
) {
2539 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
2541 InterlockedIncrement(&((struct wined3d_buffer
*)pIndexData
)->bind_count
);
2542 IWineD3DBuffer_AddRef(pIndexData
);
2545 InterlockedDecrement(&((struct wined3d_buffer
*)oldIdxs
)->bind_count
);
2546 IWineD3DBuffer_Release(oldIdxs
);
2553 static HRESULT WINAPI
IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice
*iface
, IWineD3DBuffer
**ppIndexData
)
2555 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2557 *ppIndexData
= This
->stateBlock
->pIndexData
;
2559 /* up ref count on ppindexdata */
2561 IWineD3DBuffer_AddRef(*ppIndexData
);
2562 TRACE("(%p) index data set to %p\n", This
, ppIndexData
);
2564 TRACE("(%p) No index data set\n", This
);
2566 TRACE("Returning %p\n", *ppIndexData
);
2571 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2572 static HRESULT WINAPI
IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice
*iface
, INT BaseIndex
) {
2573 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2574 TRACE("(%p)->(%d)\n", This
, BaseIndex
);
2576 if(This
->updateStateBlock
->baseVertexIndex
== BaseIndex
) {
2577 TRACE("Application is setting the old value over, nothing to do\n");
2581 This
->updateStateBlock
->baseVertexIndex
= BaseIndex
;
2583 if (This
->isRecordingState
) {
2584 TRACE("Recording... not performing anything\n");
2587 /* The base vertex index affects the stream sources */
2588 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2592 static HRESULT WINAPI
IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice
*iface
, INT
* base_index
) {
2593 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2594 TRACE("(%p) : base_index %p\n", This
, base_index
);
2596 *base_index
= This
->stateBlock
->baseVertexIndex
;
2598 TRACE("Returning %u\n", *base_index
);
2604 * Get / Set Viewports
2606 static HRESULT WINAPI
IWineD3DDeviceImpl_SetViewport(IWineD3DDevice
*iface
, CONST WINED3DVIEWPORT
* pViewport
) {
2607 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2609 TRACE("(%p)\n", This
);
2610 This
->updateStateBlock
->changed
.viewport
= TRUE
;
2611 This
->updateStateBlock
->viewport
= *pViewport
;
2613 /* Handle recording of state blocks */
2614 if (This
->isRecordingState
) {
2615 TRACE("Recording... not performing anything\n");
2619 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This
,
2620 pViewport
->X
, pViewport
->Y
, pViewport
->Width
, pViewport
->Height
, pViewport
->MinZ
, pViewport
->MaxZ
);
2622 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VIEWPORT
);
2627 static HRESULT WINAPI
IWineD3DDeviceImpl_GetViewport(IWineD3DDevice
*iface
, WINED3DVIEWPORT
* pViewport
) {
2628 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2629 TRACE("(%p)\n", This
);
2630 *pViewport
= This
->stateBlock
->viewport
;
2635 * Get / Set Render States
2636 * TODO: Verify against dx9 definitions
2638 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice
*iface
, WINED3DRENDERSTATETYPE State
, DWORD Value
) {
2640 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2641 DWORD oldValue
= This
->stateBlock
->renderState
[State
];
2643 TRACE("(%p)->state = %s(%d), value = %d\n", This
, debug_d3drenderstate(State
), State
, Value
);
2645 This
->updateStateBlock
->changed
.renderState
[State
>> 5] |= 1 << (State
& 0x1f);
2646 This
->updateStateBlock
->renderState
[State
] = Value
;
2648 /* Handle recording of state blocks */
2649 if (This
->isRecordingState
) {
2650 TRACE("Recording... not performing anything\n");
2654 /* Compared here and not before the assignment to allow proper stateblock recording */
2655 if(Value
== oldValue
) {
2656 TRACE("Application is setting the old value over, nothing to do\n");
2658 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(State
));
2664 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice
*iface
, WINED3DRENDERSTATETYPE State
, DWORD
*pValue
) {
2665 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2666 TRACE("(%p) for State %d = %d\n", This
, State
, This
->stateBlock
->renderState
[State
]);
2667 *pValue
= This
->stateBlock
->renderState
[State
];
2672 * Get / Set Sampler States
2673 * TODO: Verify against dx9 definitions
2676 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD Value
) {
2677 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2680 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2681 This
, Sampler
, debug_d3dsamplerstate(Type
), Type
, Value
);
2683 if (Sampler
>= WINED3DVERTEXTEXTURESAMPLER0
&& Sampler
<= WINED3DVERTEXTEXTURESAMPLER3
) {
2684 Sampler
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
2687 if (Sampler
>= sizeof(This
->stateBlock
->samplerState
)/sizeof(This
->stateBlock
->samplerState
[0])) {
2688 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler
);
2689 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
2692 * SetSampler is designed to allow for more than the standard up to 8 textures
2693 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2694 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2696 * http://developer.nvidia.com/object/General_FAQ.html#t6
2698 * There are two new settings for GForce
2700 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2701 * and the texture one:
2702 * GL_MAX_TEXTURE_COORDS_ARB.
2703 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2706 oldValue
= This
->stateBlock
->samplerState
[Sampler
][Type
];
2707 This
->updateStateBlock
->samplerState
[Sampler
][Type
] = Value
;
2708 This
->updateStateBlock
->changed
.samplerState
[Sampler
] |= 1 << Type
;
2710 /* Handle recording of state blocks */
2711 if (This
->isRecordingState
) {
2712 TRACE("Recording... not performing anything\n");
2716 if(oldValue
== Value
) {
2717 TRACE("Application is setting the old value over, nothing to do\n");
2721 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(Sampler
));
2726 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD
* Value
) {
2727 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2729 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2730 This
, Sampler
, debug_d3dsamplerstate(Type
), Type
);
2732 if (Sampler
>= WINED3DVERTEXTEXTURESAMPLER0
&& Sampler
<= WINED3DVERTEXTEXTURESAMPLER3
) {
2733 Sampler
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
2736 if (Sampler
>= sizeof(This
->stateBlock
->samplerState
)/sizeof(This
->stateBlock
->samplerState
[0])) {
2737 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler
);
2738 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
2740 *Value
= This
->stateBlock
->samplerState
[Sampler
][Type
];
2741 TRACE("(%p) : Returning %#x\n", This
, *Value
);
2746 static HRESULT WINAPI
IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice
*iface
, CONST RECT
* pRect
) {
2747 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2749 This
->updateStateBlock
->changed
.scissorRect
= TRUE
;
2750 if(EqualRect(&This
->updateStateBlock
->scissorRect
, pRect
)) {
2751 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2754 CopyRect(&This
->updateStateBlock
->scissorRect
, pRect
);
2756 if(This
->isRecordingState
) {
2757 TRACE("Recording... not performing anything\n");
2761 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SCISSORRECT
);
2766 static HRESULT WINAPI
IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice
*iface
, RECT
* pRect
) {
2767 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2769 *pRect
= This
->updateStateBlock
->scissorRect
;
2770 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This
, pRect
->left
, pRect
->top
, pRect
->right
, pRect
->bottom
);
2774 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
* pDecl
) {
2775 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2776 IWineD3DVertexDeclaration
*oldDecl
= This
->updateStateBlock
->vertexDecl
;
2778 TRACE("(%p) : pDecl=%p\n", This
, pDecl
);
2780 if (pDecl
) IWineD3DVertexDeclaration_AddRef(pDecl
);
2781 if (oldDecl
) IWineD3DVertexDeclaration_Release(oldDecl
);
2783 This
->updateStateBlock
->vertexDecl
= pDecl
;
2784 This
->updateStateBlock
->changed
.vertexDecl
= TRUE
;
2786 if (This
->isRecordingState
) {
2787 TRACE("Recording... not performing anything\n");
2789 } else if(pDecl
== oldDecl
) {
2790 /* Checked after the assignment to allow proper stateblock recording */
2791 TRACE("Application is setting the old declaration over, nothing to do\n");
2795 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
2799 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppDecl
) {
2800 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2802 TRACE("(%p) : ppDecl=%p\n", This
, ppDecl
);
2804 *ppDecl
= This
->stateBlock
->vertexDecl
;
2805 if (NULL
!= *ppDecl
) IWineD3DVertexDeclaration_AddRef(*ppDecl
);
2809 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
* pShader
) {
2810 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2811 IWineD3DVertexShader
* oldShader
= This
->updateStateBlock
->vertexShader
;
2813 This
->updateStateBlock
->vertexShader
= pShader
;
2814 This
->updateStateBlock
->changed
.vertexShader
= TRUE
;
2816 if (This
->isRecordingState
) {
2817 if(pShader
) IWineD3DVertexShader_AddRef(pShader
);
2818 if(oldShader
) IWineD3DVertexShader_Release(oldShader
);
2819 TRACE("Recording... not performing anything\n");
2821 } else if(oldShader
== pShader
) {
2822 /* Checked here to allow proper stateblock recording */
2823 TRACE("App is setting the old shader over, nothing to do\n");
2827 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
2828 if(pShader
) IWineD3DVertexShader_AddRef(pShader
);
2829 if(oldShader
) IWineD3DVertexShader_Release(oldShader
);
2831 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VSHADER
);
2836 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
** ppShader
) {
2837 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2839 if (NULL
== ppShader
) {
2840 return WINED3DERR_INVALIDCALL
;
2842 *ppShader
= This
->stateBlock
->vertexShader
;
2843 if( NULL
!= *ppShader
)
2844 IWineD3DVertexShader_AddRef(*ppShader
);
2846 TRACE("(%p) : returning %p\n", This
, *ppShader
);
2850 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantB(
2851 IWineD3DDevice
*iface
,
2853 CONST BOOL
*srcData
,
2856 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2857 unsigned int i
, cnt
= min(count
, MAX_CONST_B
- start
);
2859 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2860 iface
, srcData
, start
, count
);
2862 if (!srcData
|| start
>= MAX_CONST_B
) return WINED3DERR_INVALIDCALL
;
2864 memcpy(&This
->updateStateBlock
->vertexShaderConstantB
[start
], srcData
, cnt
* sizeof(BOOL
));
2865 for (i
= 0; i
< cnt
; i
++)
2866 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
2868 for (i
= start
; i
< cnt
+ start
; ++i
) {
2869 This
->updateStateBlock
->changed
.vertexShaderConstantsB
|= (1 << i
);
2872 if (!This
->isRecordingState
) IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
2877 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantB(
2878 IWineD3DDevice
*iface
,
2883 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2884 int cnt
= min(count
, MAX_CONST_B
- start
);
2886 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2887 iface
, dstData
, start
, count
);
2889 if (dstData
== NULL
|| cnt
< 0)
2890 return WINED3DERR_INVALIDCALL
;
2892 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantB
[start
], cnt
* sizeof(BOOL
));
2896 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantI(
2897 IWineD3DDevice
*iface
,
2902 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2903 unsigned int i
, cnt
= min(count
, MAX_CONST_I
- start
);
2905 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2906 iface
, srcData
, start
, count
);
2908 if (!srcData
|| start
>= MAX_CONST_I
) return WINED3DERR_INVALIDCALL
;
2910 memcpy(&This
->updateStateBlock
->vertexShaderConstantI
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
2911 for (i
= 0; i
< cnt
; i
++)
2912 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
2913 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
2915 for (i
= start
; i
< cnt
+ start
; ++i
) {
2916 This
->updateStateBlock
->changed
.vertexShaderConstantsI
|= (1 << i
);
2919 if (!This
->isRecordingState
) IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
2924 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantI(
2925 IWineD3DDevice
*iface
,
2930 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2931 int cnt
= min(count
, MAX_CONST_I
- start
);
2933 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2934 iface
, dstData
, start
, count
);
2936 if (dstData
== NULL
|| ((signed int) MAX_CONST_I
- (signed int) start
) <= (signed int) 0)
2937 return WINED3DERR_INVALIDCALL
;
2939 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantI
[start
* 4], cnt
* sizeof(int) * 4);
2943 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantF(
2944 IWineD3DDevice
*iface
,
2946 CONST
float *srcData
,
2949 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2952 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2953 iface
, srcData
, start
, count
);
2955 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
2956 if (srcData
== NULL
|| start
+ count
> This
->d3d_vshader_constantF
|| start
> This
->d3d_vshader_constantF
)
2957 return WINED3DERR_INVALIDCALL
;
2959 memcpy(&This
->updateStateBlock
->vertexShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
2961 for (i
= 0; i
< count
; i
++)
2962 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
2963 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
2966 if (!This
->isRecordingState
)
2968 This
->shader_backend
->shader_update_float_vertex_constants(iface
, start
, count
);
2969 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
2972 memset(This
->updateStateBlock
->changed
.vertexShaderConstantsF
+ start
, 1,
2973 sizeof(*This
->updateStateBlock
->changed
.vertexShaderConstantsF
) * count
);
2978 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantF(
2979 IWineD3DDevice
*iface
,
2984 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2985 int cnt
= min(count
, This
->d3d_vshader_constantF
- start
);
2987 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2988 iface
, dstData
, start
, count
);
2990 if (dstData
== NULL
|| cnt
< 0)
2991 return WINED3DERR_INVALIDCALL
;
2993 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantF
[start
* 4], cnt
* sizeof(float) * 4);
2997 static inline void markTextureStagesDirty(IWineD3DDeviceImpl
*This
, DWORD stage
) {
2999 for(i
= 0; i
<= WINED3D_HIGHEST_TEXTURE_STATE
; ++i
)
3001 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, i
));
3005 static void device_map_stage(IWineD3DDeviceImpl
*This
, DWORD stage
, DWORD unit
)
3007 DWORD i
= This
->rev_tex_unit_map
[unit
];
3008 DWORD j
= This
->texUnitMap
[stage
];
3010 This
->texUnitMap
[stage
] = unit
;
3011 if (i
!= WINED3D_UNMAPPED_STAGE
&& i
!= stage
)
3013 This
->texUnitMap
[i
] = WINED3D_UNMAPPED_STAGE
;
3016 This
->rev_tex_unit_map
[unit
] = stage
;
3017 if (j
!= WINED3D_UNMAPPED_STAGE
&& j
!= unit
)
3019 This
->rev_tex_unit_map
[j
] = WINED3D_UNMAPPED_STAGE
;
3023 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl
*This
) {
3026 This
->fixed_function_usage_map
= 0;
3027 for (i
= 0; i
< MAX_TEXTURES
; ++i
) {
3028 WINED3DTEXTUREOP color_op
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLOROP
];
3029 WINED3DTEXTUREOP alpha_op
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAOP
];
3030 DWORD color_arg1
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG1
] & WINED3DTA_SELECTMASK
;
3031 DWORD color_arg2
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG2
] & WINED3DTA_SELECTMASK
;
3032 DWORD color_arg3
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG0
] & WINED3DTA_SELECTMASK
;
3033 DWORD alpha_arg1
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG1
] & WINED3DTA_SELECTMASK
;
3034 DWORD alpha_arg2
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG2
] & WINED3DTA_SELECTMASK
;
3035 DWORD alpha_arg3
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG0
] & WINED3DTA_SELECTMASK
;
3037 if (color_op
== WINED3DTOP_DISABLE
) {
3038 /* Not used, and disable higher stages */
3042 if (((color_arg1
== WINED3DTA_TEXTURE
) && color_op
!= WINED3DTOP_SELECTARG2
)
3043 || ((color_arg2
== WINED3DTA_TEXTURE
) && color_op
!= WINED3DTOP_SELECTARG1
)
3044 || ((color_arg3
== WINED3DTA_TEXTURE
) && (color_op
== WINED3DTOP_MULTIPLYADD
|| color_op
== WINED3DTOP_LERP
))
3045 || ((alpha_arg1
== WINED3DTA_TEXTURE
) && alpha_op
!= WINED3DTOP_SELECTARG2
)
3046 || ((alpha_arg2
== WINED3DTA_TEXTURE
) && alpha_op
!= WINED3DTOP_SELECTARG1
)
3047 || ((alpha_arg3
== WINED3DTA_TEXTURE
) && (alpha_op
== WINED3DTOP_MULTIPLYADD
|| alpha_op
== WINED3DTOP_LERP
))) {
3048 This
->fixed_function_usage_map
|= (1 << i
);
3051 if ((color_op
== WINED3DTOP_BUMPENVMAP
|| color_op
== WINED3DTOP_BUMPENVMAPLUMINANCE
) && i
< MAX_TEXTURES
- 1) {
3052 This
->fixed_function_usage_map
|= (1 << (i
+ 1));
3057 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl
*This
) {
3058 unsigned int i
, tex
;
3061 device_update_fixed_function_usage_map(This
);
3062 ffu_map
= This
->fixed_function_usage_map
;
3064 if (This
->max_ffp_textures
== This
->max_ffp_texture_stages
||
3065 This
->stateBlock
->lowest_disabled_stage
<= This
->max_ffp_textures
) {
3066 for (i
= 0; ffu_map
; ffu_map
>>= 1, ++i
)
3068 if (!(ffu_map
& 1)) continue;
3070 if (This
->texUnitMap
[i
] != i
) {
3071 device_map_stage(This
, i
, i
);
3072 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3073 markTextureStagesDirty(This
, i
);
3079 /* Now work out the mapping */
3081 for (i
= 0; ffu_map
; ffu_map
>>= 1, ++i
)
3083 if (!(ffu_map
& 1)) continue;
3085 if (This
->texUnitMap
[i
] != tex
) {
3086 device_map_stage(This
, i
, tex
);
3087 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3088 markTextureStagesDirty(This
, i
);
3095 static void device_map_psamplers(IWineD3DDeviceImpl
*This
) {
3096 const WINED3DSAMPLER_TEXTURE_TYPE
*sampler_type
=
3097 ((IWineD3DPixelShaderImpl
*)This
->stateBlock
->pixelShader
)->baseShader
.reg_maps
.sampler_type
;
3100 for (i
= 0; i
< MAX_FRAGMENT_SAMPLERS
; ++i
) {
3101 if (sampler_type
[i
] && This
->texUnitMap
[i
] != i
)
3103 device_map_stage(This
, i
, i
);
3104 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3105 if (i
< MAX_TEXTURES
) {
3106 markTextureStagesDirty(This
, i
);
3112 static BOOL
device_unit_free_for_vs(IWineD3DDeviceImpl
*This
, const DWORD
*pshader_sampler_tokens
,
3113 const DWORD
*vshader_sampler_tokens
, DWORD unit
)
3115 DWORD current_mapping
= This
->rev_tex_unit_map
[unit
];
3117 /* Not currently used */
3118 if (current_mapping
== WINED3D_UNMAPPED_STAGE
) return TRUE
;
3120 if (current_mapping
< MAX_FRAGMENT_SAMPLERS
) {
3121 /* Used by a fragment sampler */
3123 if (!pshader_sampler_tokens
) {
3124 /* No pixel shader, check fixed function */
3125 return current_mapping
>= MAX_TEXTURES
|| !(This
->fixed_function_usage_map
& (1 << current_mapping
));
3128 /* Pixel shader, check the shader's sampler map */
3129 return !pshader_sampler_tokens
[current_mapping
];
3132 /* Used by a vertex sampler */
3133 return !vshader_sampler_tokens
[current_mapping
- MAX_FRAGMENT_SAMPLERS
];
3136 static void device_map_vsamplers(IWineD3DDeviceImpl
*This
, BOOL ps
) {
3137 const WINED3DSAMPLER_TEXTURE_TYPE
*vshader_sampler_type
=
3138 ((IWineD3DVertexShaderImpl
*)This
->stateBlock
->vertexShader
)->baseShader
.reg_maps
.sampler_type
;
3139 const WINED3DSAMPLER_TEXTURE_TYPE
*pshader_sampler_type
= NULL
;
3140 int start
= min(MAX_COMBINED_SAMPLERS
, This
->adapter
->gl_info
.limits
.combined_samplers
) - 1;
3144 IWineD3DPixelShaderImpl
*pshader
= (IWineD3DPixelShaderImpl
*)This
->stateBlock
->pixelShader
;
3146 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3147 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3148 pshader_sampler_type
= pshader
->baseShader
.reg_maps
.sampler_type
;
3151 for (i
= 0; i
< MAX_VERTEX_SAMPLERS
; ++i
) {
3152 DWORD vsampler_idx
= i
+ MAX_FRAGMENT_SAMPLERS
;
3153 if (vshader_sampler_type
[i
])
3155 if (This
->texUnitMap
[vsampler_idx
] != WINED3D_UNMAPPED_STAGE
)
3157 /* Already mapped somewhere */
3161 while (start
>= 0) {
3162 if (device_unit_free_for_vs(This
, pshader_sampler_type
, vshader_sampler_type
, start
))
3164 device_map_stage(This
, vsampler_idx
, start
);
3165 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(vsampler_idx
));
3177 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl
*This
) {
3178 BOOL vs
= use_vs(This
->stateBlock
);
3179 BOOL ps
= use_ps(This
->stateBlock
);
3182 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3183 * that would be really messy and require shader recompilation
3184 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3185 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3188 device_map_psamplers(This
);
3190 device_map_fixed_function_samplers(This
);
3194 device_map_vsamplers(This
, ps
);
3198 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
*pShader
) {
3199 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3200 IWineD3DPixelShader
*oldShader
= This
->updateStateBlock
->pixelShader
;
3201 This
->updateStateBlock
->pixelShader
= pShader
;
3202 This
->updateStateBlock
->changed
.pixelShader
= TRUE
;
3204 /* Handle recording of state blocks */
3205 if (This
->isRecordingState
) {
3206 TRACE("Recording... not performing anything\n");
3209 if (This
->isRecordingState
) {
3210 TRACE("Recording... not performing anything\n");
3211 if(pShader
) IWineD3DPixelShader_AddRef(pShader
);
3212 if(oldShader
) IWineD3DPixelShader_Release(oldShader
);
3216 if(pShader
== oldShader
) {
3217 TRACE("App is setting the old pixel shader over, nothing to do\n");
3221 if(pShader
) IWineD3DPixelShader_AddRef(pShader
);
3222 if(oldShader
) IWineD3DPixelShader_Release(oldShader
);
3224 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
3225 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADER
);
3230 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
**ppShader
) {
3231 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3233 if (NULL
== ppShader
) {
3234 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This
);
3235 return WINED3DERR_INVALIDCALL
;
3238 *ppShader
= This
->stateBlock
->pixelShader
;
3239 if (NULL
!= *ppShader
) {
3240 IWineD3DPixelShader_AddRef(*ppShader
);
3242 TRACE("(%p) : returning %p\n", This
, *ppShader
);
3246 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantB(
3247 IWineD3DDevice
*iface
,
3249 CONST BOOL
*srcData
,
3252 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3253 unsigned int i
, cnt
= min(count
, MAX_CONST_B
- start
);
3255 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3256 iface
, srcData
, start
, count
);
3258 if (!srcData
|| start
>= MAX_CONST_B
) return WINED3DERR_INVALIDCALL
;
3260 memcpy(&This
->updateStateBlock
->pixelShaderConstantB
[start
], srcData
, cnt
* sizeof(BOOL
));
3261 for (i
= 0; i
< cnt
; i
++)
3262 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
3264 for (i
= start
; i
< cnt
+ start
; ++i
) {
3265 This
->updateStateBlock
->changed
.pixelShaderConstantsB
|= (1 << i
);
3268 if (!This
->isRecordingState
) IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3273 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantB(
3274 IWineD3DDevice
*iface
,
3279 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3280 int cnt
= min(count
, MAX_CONST_B
- start
);
3282 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3283 iface
, dstData
, start
, count
);
3285 if (dstData
== NULL
|| cnt
< 0)
3286 return WINED3DERR_INVALIDCALL
;
3288 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantB
[start
], cnt
* sizeof(BOOL
));
3292 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantI(
3293 IWineD3DDevice
*iface
,
3298 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3299 unsigned int i
, cnt
= min(count
, MAX_CONST_I
- start
);
3301 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3302 iface
, srcData
, start
, count
);
3304 if (!srcData
|| start
>= MAX_CONST_I
) return WINED3DERR_INVALIDCALL
;
3306 memcpy(&This
->updateStateBlock
->pixelShaderConstantI
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
3307 for (i
= 0; i
< cnt
; i
++)
3308 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
3309 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3311 for (i
= start
; i
< cnt
+ start
; ++i
) {
3312 This
->updateStateBlock
->changed
.pixelShaderConstantsI
|= (1 << i
);
3315 if (!This
->isRecordingState
) IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3320 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantI(
3321 IWineD3DDevice
*iface
,
3326 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3327 int cnt
= min(count
, MAX_CONST_I
- start
);
3329 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3330 iface
, dstData
, start
, count
);
3332 if (dstData
== NULL
|| cnt
< 0)
3333 return WINED3DERR_INVALIDCALL
;
3335 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantI
[start
* 4], cnt
* sizeof(int) * 4);
3339 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantF(
3340 IWineD3DDevice
*iface
,
3342 CONST
float *srcData
,
3345 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3348 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3349 iface
, srcData
, start
, count
);
3351 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3352 if (srcData
== NULL
|| start
+ count
> This
->d3d_pshader_constantF
|| start
> This
->d3d_pshader_constantF
)
3353 return WINED3DERR_INVALIDCALL
;
3355 memcpy(&This
->updateStateBlock
->pixelShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
3357 for (i
= 0; i
< count
; i
++)
3358 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
3359 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3362 if (!This
->isRecordingState
)
3364 This
->shader_backend
->shader_update_float_pixel_constants(iface
, start
, count
);
3365 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3368 memset(This
->updateStateBlock
->changed
.pixelShaderConstantsF
+ start
, 1,
3369 sizeof(*This
->updateStateBlock
->changed
.pixelShaderConstantsF
) * count
);
3374 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantF(
3375 IWineD3DDevice
*iface
,
3380 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3381 int cnt
= min(count
, This
->d3d_pshader_constantF
- start
);
3383 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3384 iface
, dstData
, start
, count
);
3386 if (dstData
== NULL
|| cnt
< 0)
3387 return WINED3DERR_INVALIDCALL
;
3389 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantF
[start
* 4], cnt
* sizeof(float) * 4);
3393 /* Context activation is done by the caller. */
3394 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3395 static HRESULT
process_vertices_strided(IWineD3DDeviceImpl
*This
, DWORD dwDestIndex
, DWORD dwCount
,
3396 const struct wined3d_stream_info
*stream_info
, struct wined3d_buffer
*dest
, DWORD dwFlags
,
3399 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
3400 char *dest_ptr
, *dest_conv
= NULL
, *dest_conv_addr
= NULL
;
3403 WINED3DMATRIX mat
, proj_mat
, view_mat
, world_mat
;
3407 if (stream_info
->use_map
& (1 << WINED3D_FFP_NORMAL
))
3409 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3412 if (!(stream_info
->use_map
& (1 << WINED3D_FFP_POSITION
)))
3414 ERR("Source has no position mask\n");
3415 return WINED3DERR_INVALIDCALL
;
3418 /* We might access VBOs from this code, so hold the lock */
3421 if (dest
->resource
.allocatedMemory
== NULL
) {
3422 buffer_get_sysmem(dest
);
3425 /* Get a pointer into the destination vbo(create one if none exists) and
3426 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3428 if (!dest
->buffer_object
&& gl_info
->supported
[ARB_VERTEX_BUFFER_OBJECT
])
3430 dest
->flags
|= WINED3D_BUFFER_CREATEBO
;
3431 IWineD3DBuffer_PreLoad((IWineD3DBuffer
*)dest
);
3434 if (dest
->buffer_object
)
3436 unsigned char extrabytes
= 0;
3437 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3438 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3439 * this may write 4 extra bytes beyond the area that should be written
3441 if(DestFVF
== WINED3DFVF_XYZ
) extrabytes
= 4;
3442 dest_conv_addr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwCount
* get_flexible_vertex_size(DestFVF
) + extrabytes
);
3443 if(!dest_conv_addr
) {
3444 ERR("Out of memory\n");
3445 /* Continue without storing converted vertices */
3447 dest_conv
= dest_conv_addr
;
3451 * a) WINED3DRS_CLIPPING is enabled
3452 * b) WINED3DVOP_CLIP is passed
3454 if(This
->stateBlock
->renderState
[WINED3DRS_CLIPPING
]) {
3455 static BOOL warned
= FALSE
;
3457 * The clipping code is not quite correct. Some things need
3458 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3459 * so disable clipping for now.
3460 * (The graphics in Half-Life are broken, and my processvertices
3461 * test crashes with IDirect3DDevice3)
3467 FIXME("Clipping is broken and disabled for now\n");
3469 } else doClip
= FALSE
;
3470 dest_ptr
= ((char *) buffer_get_sysmem(dest
)) + dwDestIndex
* get_flexible_vertex_size(DestFVF
);
3472 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
3475 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
3476 WINED3DTS_PROJECTION
,
3478 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
3479 WINED3DTS_WORLDMATRIX(0),
3482 TRACE("View mat:\n");
3483 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
);
3484 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
);
3485 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
);
3486 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
);
3488 TRACE("Proj mat:\n");
3489 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
);
3490 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
);
3491 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
);
3492 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
);
3494 TRACE("World mat:\n");
3495 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
);
3496 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
);
3497 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
);
3498 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
);
3500 /* Get the viewport */
3501 IWineD3DDevice_GetViewport( (IWineD3DDevice
*) This
, &vp
);
3502 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3503 vp
.X
, vp
.Y
, vp
.Width
, vp
.Height
, vp
.MinZ
, vp
.MaxZ
);
3505 multiply_matrix(&mat
,&view_mat
,&world_mat
);
3506 multiply_matrix(&mat
,&proj_mat
,&mat
);
3508 numTextures
= (DestFVF
& WINED3DFVF_TEXCOUNT_MASK
) >> WINED3DFVF_TEXCOUNT_SHIFT
;
3510 for (i
= 0; i
< dwCount
; i
+= 1) {
3511 unsigned int tex_index
;
3513 if ( ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZ
) ||
3514 ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) ) {
3515 /* The position first */
3516 const struct wined3d_stream_info_element
*element
= &stream_info
->elements
[WINED3D_FFP_POSITION
];
3517 const float *p
= (const float *)(element
->data
+ i
* element
->stride
);
3519 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p
[0], p
[1], p
[2]);
3521 /* Multiplication with world, view and projection matrix */
3522 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
);
3523 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
);
3524 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
);
3525 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
);
3527 TRACE("x=%f y=%f z=%f rhw=%f\n", x
, y
, z
, rhw
);
3529 /* WARNING: The following things are taken from d3d7 and were not yet checked
3530 * against d3d8 or d3d9!
3533 /* Clipping conditions: From msdn
3535 * A vertex is clipped if it does not match the following requirements
3539 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3541 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3542 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3547 ( (-rhw
-eps
< x
) && (-rhw
-eps
< y
) && ( -eps
< z
) &&
3548 (x
<= rhw
+ eps
) && (y
<= rhw
+ eps
) && (z
<= rhw
+ eps
) &&
3551 /* "Normal" viewport transformation (not clipped)
3552 * 1) The values are divided by rhw
3553 * 2) The y axis is negative, so multiply it with -1
3554 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3555 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3556 * 4) Multiply x with Width/2 and add Width/2
3557 * 5) The same for the height
3558 * 6) Add the viewpoint X and Y to the 2D coordinates and
3559 * The minimum Z value to z
3560 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3562 * Well, basically it's simply a linear transformation into viewport
3574 z
*= vp
.MaxZ
- vp
.MinZ
;
3576 x
+= vp
.Width
/ 2 + vp
.X
;
3577 y
+= vp
.Height
/ 2 + vp
.Y
;
3582 /* That vertex got clipped
3583 * Contrary to OpenGL it is not dropped completely, it just
3584 * undergoes a different calculation.
3586 TRACE("Vertex got clipped\n");
3593 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3594 * outside of the main vertex buffer memory. That needs some more
3599 TRACE("Writing (%f %f %f) %f\n", x
, y
, z
, rhw
);
3602 ( (float *) dest_ptr
)[0] = x
;
3603 ( (float *) dest_ptr
)[1] = y
;
3604 ( (float *) dest_ptr
)[2] = z
;
3605 ( (float *) dest_ptr
)[3] = rhw
; /* SIC, see ddraw test! */
3607 dest_ptr
+= 3 * sizeof(float);
3609 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
3610 dest_ptr
+= sizeof(float);
3615 ( (float *) dest_conv
)[0] = x
* w
;
3616 ( (float *) dest_conv
)[1] = y
* w
;
3617 ( (float *) dest_conv
)[2] = z
* w
;
3618 ( (float *) dest_conv
)[3] = w
;
3620 dest_conv
+= 3 * sizeof(float);
3622 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
3623 dest_conv
+= sizeof(float);
3627 if (DestFVF
& WINED3DFVF_PSIZE
) {
3628 dest_ptr
+= sizeof(DWORD
);
3629 if(dest_conv
) dest_conv
+= sizeof(DWORD
);
3631 if (DestFVF
& WINED3DFVF_NORMAL
) {
3632 const struct wined3d_stream_info_element
*element
= &stream_info
->elements
[WINED3D_FFP_NORMAL
];
3633 const float *normal
= (const float *)(element
->data
+ i
* element
->stride
);
3634 /* AFAIK this should go into the lighting information */
3635 FIXME("Didn't expect the destination to have a normal\n");
3636 copy_and_next(dest_ptr
, normal
, 3 * sizeof(float));
3638 copy_and_next(dest_conv
, normal
, 3 * sizeof(float));
3642 if (DestFVF
& WINED3DFVF_DIFFUSE
) {
3643 const struct wined3d_stream_info_element
*element
= &stream_info
->elements
[WINED3D_FFP_DIFFUSE
];
3644 const DWORD
*color_d
= (const DWORD
*)(element
->data
+ i
* element
->stride
);
3645 if (!(stream_info
->use_map
& (1 << WINED3D_FFP_DIFFUSE
)))
3647 static BOOL warned
= FALSE
;
3650 ERR("No diffuse color in source, but destination has one\n");
3654 *( (DWORD
*) dest_ptr
) = 0xffffffff;
3655 dest_ptr
+= sizeof(DWORD
);
3658 *( (DWORD
*) dest_conv
) = 0xffffffff;
3659 dest_conv
+= sizeof(DWORD
);
3663 copy_and_next(dest_ptr
, color_d
, sizeof(DWORD
));
3665 *( (DWORD
*) dest_conv
) = (*color_d
& 0xff00ff00) ; /* Alpha + green */
3666 *( (DWORD
*) dest_conv
) |= (*color_d
& 0x00ff0000) >> 16; /* Red */
3667 *( (DWORD
*) dest_conv
) |= (*color_d
& 0xff0000ff) << 16; /* Blue */
3668 dest_conv
+= sizeof(DWORD
);
3673 if (DestFVF
& WINED3DFVF_SPECULAR
)
3675 /* What's the color value in the feedback buffer? */
3676 const struct wined3d_stream_info_element
*element
= &stream_info
->elements
[WINED3D_FFP_SPECULAR
];
3677 const DWORD
*color_s
= (const DWORD
*)(element
->data
+ i
* element
->stride
);
3678 if (!(stream_info
->use_map
& (1 << WINED3D_FFP_SPECULAR
)))
3680 static BOOL warned
= FALSE
;
3683 ERR("No specular color in source, but destination has one\n");
3687 *( (DWORD
*) dest_ptr
) = 0xFF000000;
3688 dest_ptr
+= sizeof(DWORD
);
3691 *( (DWORD
*) dest_conv
) = 0xFF000000;
3692 dest_conv
+= sizeof(DWORD
);
3696 copy_and_next(dest_ptr
, color_s
, sizeof(DWORD
));
3698 *( (DWORD
*) dest_conv
) = (*color_s
& 0xff00ff00) ; /* Alpha + green */
3699 *( (DWORD
*) dest_conv
) |= (*color_s
& 0x00ff0000) >> 16; /* Red */
3700 *( (DWORD
*) dest_conv
) |= (*color_s
& 0xff0000ff) << 16; /* Blue */
3701 dest_conv
+= sizeof(DWORD
);
3706 for (tex_index
= 0; tex_index
< numTextures
; tex_index
++) {
3707 const struct wined3d_stream_info_element
*element
= &stream_info
->elements
[WINED3D_FFP_TEXCOORD0
+ tex_index
];
3708 const float *tex_coord
= (const float *)(element
->data
+ i
* element
->stride
);
3709 if (!(stream_info
->use_map
& (1 << (WINED3D_FFP_TEXCOORD0
+ tex_index
))))
3711 ERR("No source texture, but destination requests one\n");
3712 dest_ptr
+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
3713 if(dest_conv
) dest_conv
+= GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
3716 copy_and_next(dest_ptr
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
3718 copy_and_next(dest_conv
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
3725 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, dest
->buffer_object
));
3726 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3727 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB
, dwDestIndex
* get_flexible_vertex_size(DestFVF
),
3728 dwCount
* get_flexible_vertex_size(DestFVF
),
3730 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3731 HeapFree(GetProcessHeap(), 0, dest_conv_addr
);
3738 #undef copy_and_next
3740 static HRESULT WINAPI
IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice
*iface
, UINT SrcStartIndex
, UINT DestIndex
,
3741 UINT VertexCount
, IWineD3DBuffer
*pDestBuffer
, IWineD3DVertexDeclaration
*pVertexDecl
, DWORD Flags
,
3744 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3745 struct wined3d_stream_info stream_info
;
3746 struct wined3d_context
*context
;
3747 BOOL vbo
= FALSE
, streamWasUP
= This
->stateBlock
->streamIsUP
;
3750 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This
, SrcStartIndex
, DestIndex
, VertexCount
, pDestBuffer
, pVertexDecl
, Flags
);
3753 ERR("Output vertex declaration not implemented yet\n");
3756 /* Need any context to write to the vbo. */
3757 context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
3759 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3760 * control the streamIsUP flag, thus restore it afterwards.
3762 This
->stateBlock
->streamIsUP
= FALSE
;
3763 device_stream_info_from_declaration(This
, FALSE
, &stream_info
, &vbo
);
3764 This
->stateBlock
->streamIsUP
= streamWasUP
;
3766 if(vbo
|| SrcStartIndex
) {
3768 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
3769 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
3771 * Also get the start index in, but only loop over all elements if there's something to add at all.
3773 for (i
= 0; i
< (sizeof(stream_info
.elements
) / sizeof(*stream_info
.elements
)); ++i
)
3775 struct wined3d_stream_info_element
*e
;
3777 if (!(stream_info
.use_map
& (1 << i
))) continue;
3779 e
= &stream_info
.elements
[i
];
3780 if (e
->buffer_object
)
3782 struct wined3d_buffer
*vb
= (struct wined3d_buffer
*)This
->stateBlock
->streamSource
[e
->stream_idx
];
3783 e
->buffer_object
= 0;
3784 e
->data
= (BYTE
*)((unsigned long)e
->data
+ (unsigned long)buffer_get_sysmem(vb
));
3786 GL_EXTCALL(glDeleteBuffersARB(1, &vb
->buffer_object
));
3787 vb
->buffer_object
= 0;
3790 if (e
->data
) e
->data
+= e
->stride
* SrcStartIndex
;
3794 hr
= process_vertices_strided(This
, DestIndex
, VertexCount
, &stream_info
,
3795 (struct wined3d_buffer
*)pDestBuffer
, Flags
, DestFVF
);
3797 context_release(context
);
3803 * Get / Set Texture Stage States
3804 * TODO: Verify against dx9 definitions
3806 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD Value
) {
3807 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3808 DWORD oldValue
= This
->updateStateBlock
->textureState
[Stage
][Type
];
3810 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This
, Stage
, debug_d3dtexturestate(Type
), Type
, Value
);
3812 if (Stage
>= MAX_TEXTURES
) {
3813 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage
, MAX_TEXTURES
- 1);
3817 This
->updateStateBlock
->changed
.textureState
[Stage
] |= 1 << Type
;
3818 This
->updateStateBlock
->textureState
[Stage
][Type
] = Value
;
3820 if (This
->isRecordingState
) {
3821 TRACE("Recording... not performing anything\n");
3825 /* Checked after the assignments to allow proper stateblock recording */
3826 if(oldValue
== Value
) {
3827 TRACE("App is setting the old value over, nothing to do\n");
3831 if(Stage
> This
->stateBlock
->lowest_disabled_stage
&&
3832 This
->StateTable
[STATE_TEXTURESTAGE(0, Type
)].representative
== STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP
)) {
3833 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3834 * Changes in other states are important on disabled stages too
3839 if(Type
== WINED3DTSS_COLOROP
) {
3842 if(Value
== WINED3DTOP_DISABLE
&& oldValue
!= WINED3DTOP_DISABLE
) {
3843 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3844 * they have to be disabled
3846 * The current stage is dirtified below.
3848 for(i
= Stage
+ 1; i
< This
->stateBlock
->lowest_disabled_stage
; i
++) {
3849 TRACE("Additionally dirtifying stage %u\n", i
);
3850 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
3852 This
->stateBlock
->lowest_disabled_stage
= Stage
;
3853 TRACE("New lowest disabled: %u\n", Stage
);
3854 } else if(Value
!= WINED3DTOP_DISABLE
&& oldValue
== WINED3DTOP_DISABLE
) {
3855 /* Previously disabled stage enabled. Stages above it may need enabling
3856 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3857 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3859 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3862 for (i
= Stage
+ 1; i
< This
->adapter
->gl_info
.limits
.texture_stages
; ++i
)
3864 if(This
->updateStateBlock
->textureState
[i
][WINED3DTSS_COLOROP
] == WINED3DTOP_DISABLE
) {
3867 TRACE("Additionally dirtifying stage %u due to enable\n", i
);
3868 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
3870 This
->stateBlock
->lowest_disabled_stage
= i
;
3871 TRACE("New lowest disabled: %u\n", i
);
3875 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, Type
));
3880 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD
* pValue
) {
3881 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3882 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This
, Stage
, Type
, This
->updateStateBlock
->textureState
[Stage
][Type
]);
3883 *pValue
= This
->updateStateBlock
->textureState
[Stage
][Type
];
3890 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTexture(IWineD3DDevice
*iface
,
3891 DWORD stage
, IWineD3DBaseTexture
*texture
)
3893 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3894 IWineD3DBaseTexture
*prev
;
3896 TRACE("iface %p, stage %u, texture %p.\n", iface
, stage
, texture
);
3898 if (stage
>= WINED3DVERTEXTEXTURESAMPLER0
&& stage
<= WINED3DVERTEXTEXTURESAMPLER3
)
3899 stage
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
3901 /* Windows accepts overflowing this array... we do not. */
3902 if (stage
>= sizeof(This
->stateBlock
->textures
) / sizeof(*This
->stateBlock
->textures
))
3904 WARN("Ignoring invalid stage %u.\n", stage
);
3908 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
3909 if (texture
&& ((IWineD3DTextureImpl
*)texture
)->resource
.pool
== WINED3DPOOL_SCRATCH
)
3911 WARN("Rejecting attempt to set scratch texture.\n");
3912 return WINED3DERR_INVALIDCALL
;
3915 This
->updateStateBlock
->changed
.textures
|= 1 << stage
;
3917 prev
= This
->updateStateBlock
->textures
[stage
];
3918 TRACE("Previous texture %p.\n", prev
);
3920 if (texture
== prev
)
3922 TRACE("App is setting the same texture again, nothing to do.\n");
3926 TRACE("Setting new texture to %p.\n", texture
);
3927 This
->updateStateBlock
->textures
[stage
] = texture
;
3929 if (This
->isRecordingState
)
3931 TRACE("Recording... not performing anything\n");
3933 if (texture
) IWineD3DBaseTexture_AddRef(texture
);
3934 if (prev
) IWineD3DBaseTexture_Release(prev
);
3941 IWineD3DBaseTextureImpl
*t
= (IWineD3DBaseTextureImpl
*)texture
;
3942 LONG bind_count
= InterlockedIncrement(&t
->baseTexture
.bindCount
);
3943 UINT dimensions
= IWineD3DBaseTexture_GetTextureDimensions(texture
);
3945 IWineD3DBaseTexture_AddRef(texture
);
3947 if (!prev
|| dimensions
!= IWineD3DBaseTexture_GetTextureDimensions(prev
))
3949 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADER
);
3952 if (!prev
&& stage
< MAX_TEXTURES
)
3954 /* The source arguments for color and alpha ops have different
3955 * meanings when a NULL texture is bound, so the COLOROP and
3956 * ALPHAOP have to be dirtified. */
3957 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, WINED3DTSS_COLOROP
));
3958 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, WINED3DTSS_ALPHAOP
));
3961 if (bind_count
== 1) t
->baseTexture
.sampler
= stage
;
3966 IWineD3DBaseTextureImpl
*t
= (IWineD3DBaseTextureImpl
*)prev
;
3967 LONG bind_count
= InterlockedDecrement(&t
->baseTexture
.bindCount
);
3969 IWineD3DBaseTexture_Release(prev
);
3971 if (!texture
&& stage
< MAX_TEXTURES
)
3973 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, WINED3DTSS_COLOROP
));
3974 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, WINED3DTSS_ALPHAOP
));
3977 if (bind_count
&& t
->baseTexture
.sampler
== stage
)
3981 /* Search for other stages the texture is bound to. Shouldn't
3982 * happen if applications bind textures to a single stage only. */
3983 TRACE("Searching for other stages the texture is bound to.\n");
3984 for (i
= 0; i
< MAX_COMBINED_SAMPLERS
; ++i
)
3986 if (This
->updateStateBlock
->textures
[i
] == prev
)
3988 TRACE("Texture is also bound to stage %u.\n", i
);
3989 t
->baseTexture
.sampler
= i
;
3996 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(stage
));
4001 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTexture(IWineD3DDevice
*iface
, DWORD Stage
, IWineD3DBaseTexture
** ppTexture
) {
4002 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4004 TRACE("(%p) : Stage %#x, ppTexture %p\n", This
, Stage
, ppTexture
);
4006 if (Stage
>= WINED3DVERTEXTEXTURESAMPLER0
&& Stage
<= WINED3DVERTEXTEXTURESAMPLER3
) {
4007 Stage
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
4010 if (Stage
>= sizeof(This
->stateBlock
->textures
)/sizeof(This
->stateBlock
->textures
[0])) {
4011 ERR("Current stage overflows textures array (stage %d)\n", Stage
);
4012 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
4015 *ppTexture
=This
->stateBlock
->textures
[Stage
];
4017 IWineD3DBaseTexture_AddRef(*ppTexture
);
4019 TRACE("(%p) : Returning %p\n", This
, *ppTexture
);
4027 static HRESULT WINAPI
IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice
*iface
, UINT swapchain_idx
,
4028 UINT backbuffer_idx
, WINED3DBACKBUFFER_TYPE backbuffer_type
, IWineD3DSurface
**backbuffer
)
4030 IWineD3DSwapChain
*swapchain
;
4033 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4034 iface
, swapchain_idx
, backbuffer_idx
, backbuffer_type
, backbuffer
);
4036 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, swapchain_idx
, &swapchain
);
4039 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx
, hr
);
4043 hr
= IWineD3DSwapChain_GetBackBuffer(swapchain
, backbuffer_idx
, backbuffer_type
, backbuffer
);
4044 IWineD3DSwapChain_Release(swapchain
);
4047 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx
, hr
);
4054 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice
*iface
, WINED3DCAPS
* pCaps
) {
4055 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4056 WARN("(%p) : stub, calling idirect3d for now\n", This
);
4057 return IWineD3D_GetDeviceCaps(This
->wined3d
, This
->adapter
->ordinal
, This
->devType
, pCaps
);
4060 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DDISPLAYMODE
* pMode
) {
4061 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4062 IWineD3DSwapChain
*swapChain
;
4065 if(iSwapChain
> 0) {
4066 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
4067 if (hr
== WINED3D_OK
) {
4068 hr
= IWineD3DSwapChain_GetDisplayMode(swapChain
, pMode
);
4069 IWineD3DSwapChain_Release(swapChain
);
4071 FIXME("(%p) Error getting display mode\n", This
);
4074 /* Don't read the real display mode,
4075 but return the stored mode instead. X11 can't change the color
4076 depth, and some apps are pretty angry if they SetDisplayMode from
4077 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4079 Also don't relay to the swapchain because with ddraw it's possible
4080 that there isn't a swapchain at all */
4081 pMode
->Width
= This
->ddraw_width
;
4082 pMode
->Height
= This
->ddraw_height
;
4083 pMode
->Format
= This
->ddraw_format
;
4084 pMode
->RefreshRate
= 0;
4092 * Stateblock related functions
4095 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice
*iface
) {
4096 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4097 IWineD3DStateBlock
*stateblock
;
4100 TRACE("(%p)\n", This
);
4102 if (This
->isRecordingState
) return WINED3DERR_INVALIDCALL
;
4104 hr
= IWineD3DDeviceImpl_CreateStateBlock(iface
, WINED3DSBT_RECORDED
, &stateblock
, NULL
);
4105 if (FAILED(hr
)) return hr
;
4107 IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
);
4108 This
->updateStateBlock
= (IWineD3DStateBlockImpl
*)stateblock
;
4109 This
->isRecordingState
= TRUE
;
4111 TRACE("(%p) recording stateblock %p\n", This
, stateblock
);
4116 static HRESULT WINAPI
IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice
*iface
, IWineD3DStateBlock
** ppStateBlock
) {
4117 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4118 IWineD3DStateBlockImpl
*object
= This
->updateStateBlock
;
4120 if (!This
->isRecordingState
) {
4121 WARN("(%p) not recording! returning error\n", This
);
4122 *ppStateBlock
= NULL
;
4123 return WINED3DERR_INVALIDCALL
;
4126 stateblock_init_contained_states(object
);
4128 *ppStateBlock
= (IWineD3DStateBlock
*) object
;
4129 This
->isRecordingState
= FALSE
;
4130 This
->updateStateBlock
= This
->stateBlock
;
4131 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
4132 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4133 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This
, *ppStateBlock
);
4138 * Scene related functions
4140 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginScene(IWineD3DDevice
*iface
) {
4141 /* At the moment we have no need for any functionality at the beginning
4143 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4144 TRACE("(%p)\n", This
);
4147 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4148 return WINED3DERR_INVALIDCALL
;
4150 This
->inScene
= TRUE
;
4154 static HRESULT WINAPI
IWineD3DDeviceImpl_EndScene(IWineD3DDevice
*iface
)
4156 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4157 struct wined3d_context
*context
;
4159 TRACE("(%p)\n", This
);
4161 if(!This
->inScene
) {
4162 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4163 return WINED3DERR_INVALIDCALL
;
4166 context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
4167 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4169 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4171 context_release(context
);
4173 This
->inScene
= FALSE
;
4177 static HRESULT WINAPI
IWineD3DDeviceImpl_Present(IWineD3DDevice
*iface
,
4178 const RECT
*pSourceRect
, const RECT
*pDestRect
,
4179 HWND hDestWindowOverride
, const RGNDATA
*pDirtyRegion
)
4181 IWineD3DSwapChain
*swapChain
= NULL
;
4183 int swapchains
= IWineD3DDeviceImpl_GetNumberOfSwapChains(iface
);
4185 TRACE("iface %p.\n", iface
);
4187 for(i
= 0 ; i
< swapchains
; i
++) {
4189 IWineD3DDeviceImpl_GetSwapChain(iface
, i
, &swapChain
);
4190 TRACE("presentinng chain %d, %p\n", i
, swapChain
);
4191 IWineD3DSwapChain_Present(swapChain
, pSourceRect
, pDestRect
, hDestWindowOverride
, pDirtyRegion
, 0);
4192 IWineD3DSwapChain_Release(swapChain
);
4198 /* Not called from the VTable (internal subroutine) */
4199 HRESULT
IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl
*This
, IWineD3DSurfaceImpl
*target
, DWORD Count
,
4200 CONST WINED3DRECT
* pRects
, DWORD Flags
, WINED3DCOLOR Color
,
4201 float Z
, DWORD Stencil
) {
4202 GLbitfield glMask
= 0;
4204 WINED3DRECT curRect
;
4206 const WINED3DVIEWPORT
*vp
= &This
->stateBlock
->viewport
;
4207 UINT drawable_width
, drawable_height
;
4208 IWineD3DSurfaceImpl
*depth_stencil
= (IWineD3DSurfaceImpl
*) This
->stencilBufferTarget
;
4209 IWineD3DSwapChainImpl
*swapchain
= NULL
;
4210 struct wined3d_context
*context
;
4212 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4213 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4214 * for the cleared parts, and the untouched parts.
4216 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4217 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4218 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4219 * checking all this if the dest surface is in the drawable anyway.
4221 if((Flags
& WINED3DCLEAR_TARGET
) && !(target
->Flags
& SFLAG_INDRAWABLE
)) {
4223 if(vp
->X
!= 0 || vp
->Y
!= 0 ||
4224 vp
->Width
< target
->currentDesc
.Width
|| vp
->Height
< target
->currentDesc
.Height
) {
4225 IWineD3DSurface_LoadLocation((IWineD3DSurface
*) target
, SFLAG_INDRAWABLE
, NULL
);
4228 if(This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
] && (
4229 This
->stateBlock
->scissorRect
.left
> 0 || This
->stateBlock
->scissorRect
.top
> 0 ||
4230 This
->stateBlock
->scissorRect
.right
< target
->currentDesc
.Width
||
4231 This
->stateBlock
->scissorRect
.bottom
< target
->currentDesc
.Height
)) {
4232 IWineD3DSurface_LoadLocation((IWineD3DSurface
*) target
, SFLAG_INDRAWABLE
, NULL
);
4235 if(Count
> 0 && pRects
&& (
4236 pRects
[0].x1
> 0 || pRects
[0].y1
> 0 ||
4237 pRects
[0].x2
< target
->currentDesc
.Width
||
4238 pRects
[0].y2
< target
->currentDesc
.Height
)) {
4239 IWineD3DSurface_LoadLocation((IWineD3DSurface
*) target
, SFLAG_INDRAWABLE
, NULL
);
4246 context
= context_acquire(This
, (IWineD3DSurface
*)target
, CTXUSAGE_CLEAR
);
4248 target
->get_drawable_size(context
, &drawable_width
, &drawable_height
);
4252 /* Only set the values up once, as they are not changing */
4253 if (Flags
& WINED3DCLEAR_STENCIL
) {
4254 glClearStencil(Stencil
);
4255 checkGLcall("glClearStencil");
4256 glMask
= glMask
| GL_STENCIL_BUFFER_BIT
;
4257 glStencilMask(0xFFFFFFFF);
4260 if (Flags
& WINED3DCLEAR_ZBUFFER
) {
4261 DWORD location
= context
->render_offscreen
? SFLAG_DS_OFFSCREEN
: SFLAG_DS_ONSCREEN
;
4262 glDepthMask(GL_TRUE
);
4264 checkGLcall("glClearDepth");
4265 glMask
= glMask
| GL_DEPTH_BUFFER_BIT
;
4266 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ZWRITEENABLE
));
4268 if (vp
->X
!= 0 || vp
->Y
!= 0 ||
4269 vp
->Width
< depth_stencil
->currentDesc
.Width
|| vp
->Height
< depth_stencil
->currentDesc
.Height
) {
4270 surface_load_ds_location(This
->stencilBufferTarget
, context
, location
);
4272 else if (This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
] && (
4273 This
->stateBlock
->scissorRect
.left
> 0 || This
->stateBlock
->scissorRect
.top
> 0 ||
4274 This
->stateBlock
->scissorRect
.right
< depth_stencil
->currentDesc
.Width
||
4275 This
->stateBlock
->scissorRect
.bottom
< depth_stencil
->currentDesc
.Height
)) {
4276 surface_load_ds_location(This
->stencilBufferTarget
, context
, location
);
4278 else if (Count
> 0 && pRects
&& (
4279 pRects
[0].x1
> 0 || pRects
[0].y1
> 0 ||
4280 pRects
[0].x2
< depth_stencil
->currentDesc
.Width
||
4281 pRects
[0].y2
< depth_stencil
->currentDesc
.Height
)) {
4282 surface_load_ds_location(This
->stencilBufferTarget
, context
, location
);
4286 if (Flags
& WINED3DCLEAR_TARGET
) {
4287 TRACE("Clearing screen with glClear to color %x\n", Color
);
4288 glClearColor(D3DCOLOR_R(Color
),
4292 checkGLcall("glClearColor");
4294 /* Clear ALL colors! */
4295 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
4296 glMask
= glMask
| GL_COLOR_BUFFER_BIT
;
4299 vp_rect
.left
= vp
->X
;
4300 vp_rect
.top
= vp
->Y
;
4301 vp_rect
.right
= vp
->X
+ vp
->Width
;
4302 vp_rect
.bottom
= vp
->Y
+ vp
->Height
;
4303 if (!(Count
> 0 && pRects
)) {
4304 if(This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
]) {
4305 IntersectRect(&vp_rect
, &vp_rect
, &This
->stateBlock
->scissorRect
);
4307 if (context
->render_offscreen
)
4309 glScissor(vp_rect
.left
, vp_rect
.top
,
4310 vp_rect
.right
- vp_rect
.left
, vp_rect
.bottom
- vp_rect
.top
);
4312 glScissor(vp_rect
.left
, drawable_height
- vp_rect
.bottom
,
4313 vp_rect
.right
- vp_rect
.left
, vp_rect
.bottom
- vp_rect
.top
);
4315 checkGLcall("glScissor");
4317 checkGLcall("glClear");
4319 /* Now process each rect in turn */
4320 for (i
= 0; i
< Count
; i
++) {
4321 /* Note gl uses lower left, width/height */
4322 IntersectRect((RECT
*)&curRect
, &vp_rect
, (const RECT
*)&pRects
[i
]);
4323 if(This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
]) {
4324 IntersectRect((RECT
*) &curRect
, (RECT
*) &curRect
, &This
->stateBlock
->scissorRect
);
4326 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This
,
4327 pRects
[i
].x1
, pRects
[i
].y1
, pRects
[i
].x2
, pRects
[i
].y2
,
4328 curRect
.x1
, (target
->currentDesc
.Height
- curRect
.y2
),
4329 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
4331 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4332 * The rectangle is not cleared, no error is returned, but further rectanlges are
4333 * still cleared if they are valid
4335 if(curRect
.x1
> curRect
.x2
|| curRect
.y1
> curRect
.y2
) {
4336 TRACE("Rectangle with negative dimensions, ignoring\n");
4340 if (context
->render_offscreen
)
4342 glScissor(curRect
.x1
, curRect
.y1
,
4343 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
4345 glScissor(curRect
.x1
, drawable_height
- curRect
.y2
,
4346 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
4348 checkGLcall("glScissor");
4351 checkGLcall("glClear");
4355 /* Restore the old values (why..?) */
4356 if (Flags
& WINED3DCLEAR_STENCIL
) {
4357 glStencilMask(This
->stateBlock
->renderState
[WINED3DRS_STENCILWRITEMASK
]);
4359 if (Flags
& WINED3DCLEAR_TARGET
) {
4360 DWORD mask
= This
->stateBlock
->renderState
[WINED3DRS_COLORWRITEENABLE
];
4361 glColorMask(mask
& WINED3DCOLORWRITEENABLE_RED
? GL_TRUE
: GL_FALSE
,
4362 mask
& WINED3DCOLORWRITEENABLE_GREEN
? GL_TRUE
: GL_FALSE
,
4363 mask
& WINED3DCOLORWRITEENABLE_BLUE
? GL_TRUE
: GL_FALSE
,
4364 mask
& WINED3DCOLORWRITEENABLE_ALPHA
? GL_TRUE
: GL_FALSE
);
4366 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4367 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4369 IWineD3DSurface_ModifyLocation((IWineD3DSurface
*)target
, SFLAG_INDRAWABLE
, TRUE
);
4371 if (Flags
& WINED3DCLEAR_ZBUFFER
) {
4372 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
4373 DWORD location
= context
->render_offscreen
? SFLAG_DS_OFFSCREEN
: SFLAG_DS_ONSCREEN
;
4374 surface_modify_ds_location(This
->stencilBufferTarget
, location
);
4379 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface
*)target
, &IID_IWineD3DSwapChain
, (void **)&swapchain
))) {
4380 if (target
== (IWineD3DSurfaceImpl
*) swapchain
->frontBuffer
) {
4383 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
4386 context_release(context
);
4391 static HRESULT WINAPI
IWineD3DDeviceImpl_Clear(IWineD3DDevice
*iface
, DWORD Count
, CONST WINED3DRECT
* pRects
,
4392 DWORD Flags
, WINED3DCOLOR Color
, float Z
, DWORD Stencil
) {
4393 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4394 IWineD3DSurfaceImpl
*target
= (IWineD3DSurfaceImpl
*)This
->render_targets
[0];
4396 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This
,
4397 Count
, pRects
, Flags
, Color
, Z
, Stencil
);
4399 if(Flags
& (WINED3DCLEAR_ZBUFFER
| WINED3DCLEAR_STENCIL
) && This
->stencilBufferTarget
== NULL
) {
4400 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4401 /* TODO: What about depth stencil buffers without stencil bits? */
4402 return WINED3DERR_INVALIDCALL
;
4405 return IWineD3DDeviceImpl_ClearSurface(This
, target
, Count
, pRects
, Flags
, Color
, Z
, Stencil
);
4412 static void WINAPI
IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice
*iface
,
4413 WINED3DPRIMITIVETYPE primitive_type
)
4415 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4417 TRACE("iface %p, primitive_type %s\n", iface
, debug_d3dprimitivetype(primitive_type
));
4419 This
->updateStateBlock
->changed
.primitive_type
= TRUE
;
4420 This
->updateStateBlock
->gl_primitive_type
= gl_primitive_type_from_d3d(primitive_type
);
4423 static void WINAPI
IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice
*iface
,
4424 WINED3DPRIMITIVETYPE
*primitive_type
)
4426 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4428 TRACE("iface %p, primitive_type %p\n", iface
, primitive_type
);
4430 *primitive_type
= d3d_primitive_type_from_gl(This
->stateBlock
->gl_primitive_type
);
4432 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type
));
4435 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice
*iface
, UINT StartVertex
, UINT vertex_count
)
4437 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4439 TRACE("(%p) : start %u, count %u\n", This
, StartVertex
, vertex_count
);
4441 if(!This
->stateBlock
->vertexDecl
) {
4442 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
4443 return WINED3DERR_INVALIDCALL
;
4446 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4447 if(This
->stateBlock
->streamIsUP
) {
4448 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
4449 This
->stateBlock
->streamIsUP
= FALSE
;
4452 if(This
->stateBlock
->loadBaseVertexIndex
!= 0) {
4453 This
->stateBlock
->loadBaseVertexIndex
= 0;
4454 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
4456 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4457 drawPrimitive(iface
, vertex_count
, StartVertex
/* start_idx */, 0 /* indxSize */, NULL
/* indxData */);
4461 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice
*iface
, UINT startIndex
, UINT index_count
)
4463 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4465 IWineD3DBuffer
*pIB
;
4468 pIB
= This
->stateBlock
->pIndexData
;
4470 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4471 * without an index buffer set. (The first time at least...)
4472 * D3D8 simply dies, but I doubt it can do much harm to return
4473 * D3DERR_INVALIDCALL there as well. */
4474 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This
);
4475 return WINED3DERR_INVALIDCALL
;
4478 if(!This
->stateBlock
->vertexDecl
) {
4479 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
4480 return WINED3DERR_INVALIDCALL
;
4483 if(This
->stateBlock
->streamIsUP
) {
4484 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
4485 This
->stateBlock
->streamIsUP
= FALSE
;
4487 vbo
= ((struct wined3d_buffer
*) pIB
)->buffer_object
;
4489 TRACE("(%p) : startIndex %u, index count %u.\n", This
, startIndex
, index_count
);
4491 if (This
->stateBlock
->IndexFmt
== WINED3DFMT_R16_UINT
) {
4497 if(This
->stateBlock
->loadBaseVertexIndex
!= This
->stateBlock
->baseVertexIndex
) {
4498 This
->stateBlock
->loadBaseVertexIndex
= This
->stateBlock
->baseVertexIndex
;
4499 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
4502 drawPrimitive(iface
, index_count
, startIndex
, idxStride
,
4503 vbo
? NULL
: ((struct wined3d_buffer
*)pIB
)->resource
.allocatedMemory
);
4508 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice
*iface
, UINT vertex_count
,
4509 const void *pVertexStreamZeroData
, UINT VertexStreamZeroStride
)
4511 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4514 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4515 This
, vertex_count
, pVertexStreamZeroData
, VertexStreamZeroStride
);
4517 if(!This
->stateBlock
->vertexDecl
) {
4518 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
4519 return WINED3DERR_INVALIDCALL
;
4522 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4523 vb
= This
->stateBlock
->streamSource
[0];
4524 This
->stateBlock
->streamSource
[0] = (IWineD3DBuffer
*)pVertexStreamZeroData
;
4525 if (vb
) IWineD3DBuffer_Release(vb
);
4526 This
->stateBlock
->streamOffset
[0] = 0;
4527 This
->stateBlock
->streamStride
[0] = VertexStreamZeroStride
;
4528 This
->stateBlock
->streamIsUP
= TRUE
;
4529 This
->stateBlock
->loadBaseVertexIndex
= 0;
4531 /* TODO: Only mark dirty if drawing from a different UP address */
4532 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
4534 drawPrimitive(iface
, vertex_count
, 0 /* start_idx */, 0 /* indxSize*/, NULL
/* indxData */);
4536 /* MSDN specifies stream zero settings must be set to NULL */
4537 This
->stateBlock
->streamStride
[0] = 0;
4538 This
->stateBlock
->streamSource
[0] = NULL
;
4540 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4541 * the new stream sources or use UP drawing again
4546 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice
*iface
,
4547 UINT index_count
, const void *pIndexData
, WINED3DFORMAT IndexDataFormat
,
4548 const void *pVertexStreamZeroData
, UINT VertexStreamZeroStride
)
4551 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4555 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4556 This
, index_count
, pIndexData
, IndexDataFormat
, pVertexStreamZeroData
, VertexStreamZeroStride
);
4558 if(!This
->stateBlock
->vertexDecl
) {
4559 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
4560 return WINED3DERR_INVALIDCALL
;
4563 if (IndexDataFormat
== WINED3DFMT_R16_UINT
) {
4569 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4570 vb
= This
->stateBlock
->streamSource
[0];
4571 This
->stateBlock
->streamSource
[0] = (IWineD3DBuffer
*)pVertexStreamZeroData
;
4572 if (vb
) IWineD3DBuffer_Release(vb
);
4573 This
->stateBlock
->streamIsUP
= TRUE
;
4574 This
->stateBlock
->streamOffset
[0] = 0;
4575 This
->stateBlock
->streamStride
[0] = VertexStreamZeroStride
;
4577 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4578 This
->stateBlock
->baseVertexIndex
= 0;
4579 This
->stateBlock
->loadBaseVertexIndex
= 0;
4580 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4581 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
4582 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
4584 drawPrimitive(iface
, index_count
, 0 /* start_idx */, idxStride
, pIndexData
);
4586 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4587 This
->stateBlock
->streamSource
[0] = NULL
;
4588 This
->stateBlock
->streamStride
[0] = 0;
4589 ib
= This
->stateBlock
->pIndexData
;
4591 IWineD3DBuffer_Release(ib
);
4592 This
->stateBlock
->pIndexData
= NULL
;
4594 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4595 * SetStreamSource to specify a vertex buffer
4601 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice
*iface
,
4602 UINT vertex_count
, const WineDirect3DVertexStridedData
*DrawPrimStrideData
)
4604 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
4606 /* Mark the state dirty until we have nicer tracking
4607 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4610 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
4611 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
4612 This
->stateBlock
->baseVertexIndex
= 0;
4613 This
->up_strided
= DrawPrimStrideData
;
4614 drawPrimitive(iface
, vertex_count
, 0, 0, NULL
);
4615 This
->up_strided
= NULL
;
4619 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice
*iface
,
4620 UINT vertex_count
, const WineDirect3DVertexStridedData
*DrawPrimStrideData
,
4621 UINT NumVertices
, const void *pIndexData
, WINED3DFORMAT IndexDataFormat
)
4623 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
4624 DWORD idxSize
= (IndexDataFormat
== WINED3DFMT_R32_UINT
? 4 : 2);
4626 /* Mark the state dirty until we have nicer tracking
4627 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4630 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
4631 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
4632 This
->stateBlock
->streamIsUP
= TRUE
;
4633 This
->stateBlock
->baseVertexIndex
= 0;
4634 This
->up_strided
= DrawPrimStrideData
;
4635 drawPrimitive(iface
, vertex_count
, 0 /* start_idx */, idxSize
, pIndexData
);
4636 This
->up_strided
= NULL
;
4640 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4641 static HRESULT
IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice
*iface
,
4642 IWineD3DVolume
*pSourceVolume
, IWineD3DVolume
*pDestinationVolume
)
4644 WINED3DLOCKED_BOX src
;
4645 WINED3DLOCKED_BOX dst
;
4648 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4649 iface
, pSourceVolume
, pDestinationVolume
);
4651 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4652 * dirtification to improve loading performance.
4654 hr
= IWineD3DVolume_LockBox(pSourceVolume
, &src
, NULL
, WINED3DLOCK_READONLY
);
4655 if(FAILED(hr
)) return hr
;
4656 hr
= IWineD3DVolume_LockBox(pDestinationVolume
, &dst
, NULL
, WINED3DLOCK_DISCARD
);
4658 IWineD3DVolume_UnlockBox(pSourceVolume
);
4662 memcpy(dst
.pBits
, src
.pBits
, ((IWineD3DVolumeImpl
*) pDestinationVolume
)->resource
.size
);
4664 hr
= IWineD3DVolume_UnlockBox(pDestinationVolume
);
4666 IWineD3DVolume_UnlockBox(pSourceVolume
);
4668 hr
= IWineD3DVolume_UnlockBox(pSourceVolume
);
4673 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice
*iface
,
4674 IWineD3DBaseTexture
*src_texture
, IWineD3DBaseTexture
*dst_texture
)
4676 unsigned int level_count
, i
;
4677 WINED3DRESOURCETYPE type
;
4680 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface
, src_texture
, dst_texture
);
4682 /* Verify that the source and destination textures are non-NULL. */
4683 if (!src_texture
|| !dst_texture
)
4685 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4686 return WINED3DERR_INVALIDCALL
;
4689 if (src_texture
== dst_texture
)
4691 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4692 return WINED3DERR_INVALIDCALL
;
4695 /* Verify that the source and destination textures are the same type. */
4696 type
= IWineD3DBaseTexture_GetType(src_texture
);
4697 if (IWineD3DBaseTexture_GetType(dst_texture
) != type
)
4699 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4700 return WINED3DERR_INVALIDCALL
;
4703 /* Check that both textures have the identical numbers of levels. */
4704 level_count
= IWineD3DBaseTexture_GetLevelCount(src_texture
);
4705 if (IWineD3DBaseTexture_GetLevelCount(dst_texture
) != level_count
)
4707 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4708 return WINED3DERR_INVALIDCALL
;
4711 /* Make sure that the destination texture is loaded. */
4712 ((IWineD3DBaseTextureImpl
*)dst_texture
)->baseTexture
.internal_preload(dst_texture
, SRGB_RGB
);
4714 /* Update every surface level of the texture. */
4717 case WINED3DRTYPE_TEXTURE
:
4719 IWineD3DSurface
*src_surface
;
4720 IWineD3DSurface
*dst_surface
;
4722 for (i
= 0; i
< level_count
; ++i
)
4724 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)src_texture
, i
, &src_surface
);
4725 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)dst_texture
, i
, &dst_surface
);
4726 hr
= IWineD3DDevice_UpdateSurface(iface
, src_surface
, NULL
, dst_surface
, NULL
);
4727 IWineD3DSurface_Release(dst_surface
);
4728 IWineD3DSurface_Release(src_surface
);
4731 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr
);
4738 case WINED3DRTYPE_CUBETEXTURE
:
4740 IWineD3DSurface
*src_surface
;
4741 IWineD3DSurface
*dst_surface
;
4742 WINED3DCUBEMAP_FACES face
;
4744 for (i
= 0; i
< level_count
; ++i
)
4746 /* Update each cube face. */
4747 for (face
= WINED3DCUBEMAP_FACE_POSITIVE_X
; face
<= WINED3DCUBEMAP_FACE_NEGATIVE_Z
; ++face
)
4749 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)src_texture
,
4750 face
, i
, &src_surface
);
4751 if (FAILED(hr
)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face
, i
, hr
);
4752 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)dst_texture
,
4753 face
, i
, &dst_surface
);
4754 if (FAILED(hr
)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face
, i
, hr
);
4755 hr
= IWineD3DDevice_UpdateSurface(iface
, src_surface
, NULL
, dst_surface
, NULL
);
4756 IWineD3DSurface_Release(dst_surface
);
4757 IWineD3DSurface_Release(src_surface
);
4760 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr
);
4768 case WINED3DRTYPE_VOLUMETEXTURE
:
4770 IWineD3DVolume
*src_volume
;
4771 IWineD3DVolume
*dst_volume
;
4773 for (i
= 0; i
< level_count
; ++i
)
4775 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture
*)src_texture
, i
, &src_volume
);
4776 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture
*)dst_texture
, i
, &dst_volume
);
4777 hr
= IWineD3DDeviceImpl_UpdateVolume(iface
, src_volume
, dst_volume
);
4778 IWineD3DVolume_Release(dst_volume
);
4779 IWineD3DVolume_Release(src_volume
);
4782 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr
);
4790 FIXME("Unsupported texture type %#x.\n", type
);
4791 return WINED3DERR_INVALIDCALL
;
4797 static HRESULT WINAPI
IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice
*iface
,UINT iSwapChain
, IWineD3DSurface
*pDestSurface
) {
4798 IWineD3DSwapChain
*swapChain
;
4800 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
4801 if(hr
== WINED3D_OK
) {
4802 hr
= IWineD3DSwapChain_GetFrontBufferData(swapChain
, pDestSurface
);
4803 IWineD3DSwapChain_Release(swapChain
);
4808 static HRESULT WINAPI
IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice
*iface
, DWORD
* pNumPasses
) {
4809 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4810 IWineD3DBaseTextureImpl
*texture
;
4813 TRACE("(%p) : %p\n", This
, pNumPasses
);
4815 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++) {
4816 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MINFILTER
] == WINED3DTEXF_NONE
) {
4817 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i
);
4818 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER
;
4820 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MAGFILTER
] == WINED3DTEXF_NONE
) {
4821 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i
);
4822 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER
;
4825 texture
= (IWineD3DBaseTextureImpl
*) This
->stateBlock
->textures
[i
];
4826 if (!texture
|| texture
->resource
.format_desc
->Flags
& WINED3DFMT_FLAG_FILTERING
) continue;
4828 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MAGFILTER
] != WINED3DTEXF_POINT
) {
4829 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i
);
4832 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MINFILTER
] != WINED3DTEXF_POINT
) {
4833 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i
);
4836 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MIPFILTER
] != WINED3DTEXF_NONE
&&
4837 This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MIPFILTER
] != WINED3DTEXF_POINT
/* sic! */) {
4838 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i
);
4843 /* return a sensible default */
4846 TRACE("returning D3D_OK\n");
4850 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl
*device
)
4854 for (i
= 0; i
< MAX_COMBINED_SAMPLERS
; ++i
)
4856 IWineD3DBaseTextureImpl
*texture
= (IWineD3DBaseTextureImpl
*)device
->stateBlock
->textures
[i
];
4857 if (texture
&& (texture
->resource
.format_desc
->format
== WINED3DFMT_P8_UINT
4858 || texture
->resource
.format_desc
->format
== WINED3DFMT_P8_UINT_A8_UNORM
))
4860 IWineD3DDeviceImpl_MarkStateDirty(device
, STATE_SAMPLER(i
));
4865 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, CONST PALETTEENTRY
* pEntries
) {
4866 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4869 PALETTEENTRY
**palettes
;
4871 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
4873 if (PaletteNumber
>= MAX_PALETTES
) {
4874 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This
, PaletteNumber
, MAX_PALETTES
);
4875 return WINED3DERR_INVALIDCALL
;
4878 if (PaletteNumber
>= This
->NumberOfPalettes
) {
4879 NewSize
= This
->NumberOfPalettes
;
4882 } while(PaletteNumber
>= NewSize
);
4883 palettes
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, This
->palettes
, sizeof(PALETTEENTRY
*) * NewSize
);
4885 ERR("Out of memory!\n");
4886 return E_OUTOFMEMORY
;
4888 This
->palettes
= palettes
;
4889 This
->NumberOfPalettes
= NewSize
;
4892 if (!This
->palettes
[PaletteNumber
]) {
4893 This
->palettes
[PaletteNumber
] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY
) * 256);
4894 if (!This
->palettes
[PaletteNumber
]) {
4895 ERR("Out of memory!\n");
4896 return E_OUTOFMEMORY
;
4900 for (j
= 0; j
< 256; ++j
) {
4901 This
->palettes
[PaletteNumber
][j
].peRed
= pEntries
[j
].peRed
;
4902 This
->palettes
[PaletteNumber
][j
].peGreen
= pEntries
[j
].peGreen
;
4903 This
->palettes
[PaletteNumber
][j
].peBlue
= pEntries
[j
].peBlue
;
4904 This
->palettes
[PaletteNumber
][j
].peFlags
= pEntries
[j
].peFlags
;
4906 if (PaletteNumber
== This
->currentPalette
) dirtify_p8_texture_samplers(This
);
4907 TRACE("(%p) : returning\n", This
);
4911 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, PALETTEENTRY
* pEntries
) {
4912 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4914 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
4915 if (PaletteNumber
>= This
->NumberOfPalettes
|| !This
->palettes
[PaletteNumber
]) {
4916 /* What happens in such situation isn't documented; Native seems to silently abort
4917 on such conditions. Return Invalid Call. */
4918 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This
, PaletteNumber
, This
->NumberOfPalettes
);
4919 return WINED3DERR_INVALIDCALL
;
4921 for (j
= 0; j
< 256; ++j
) {
4922 pEntries
[j
].peRed
= This
->palettes
[PaletteNumber
][j
].peRed
;
4923 pEntries
[j
].peGreen
= This
->palettes
[PaletteNumber
][j
].peGreen
;
4924 pEntries
[j
].peBlue
= This
->palettes
[PaletteNumber
][j
].peBlue
;
4925 pEntries
[j
].peFlags
= This
->palettes
[PaletteNumber
][j
].peFlags
;
4927 TRACE("(%p) : returning\n", This
);
4931 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT PaletteNumber
) {
4932 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4933 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
4934 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
4935 (tested with reference rasterizer). Return Invalid Call. */
4936 if (PaletteNumber
>= This
->NumberOfPalettes
|| !This
->palettes
[PaletteNumber
]) {
4937 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This
, PaletteNumber
, This
->NumberOfPalettes
);
4938 return WINED3DERR_INVALIDCALL
;
4940 /*TODO: stateblocks */
4941 if (This
->currentPalette
!= PaletteNumber
) {
4942 This
->currentPalette
= PaletteNumber
;
4943 dirtify_p8_texture_samplers(This
);
4945 TRACE("(%p) : returning\n", This
);
4949 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT
* PaletteNumber
) {
4950 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4951 if (PaletteNumber
== NULL
) {
4952 WARN("(%p) : returning Invalid Call\n", This
);
4953 return WINED3DERR_INVALIDCALL
;
4955 /*TODO: stateblocks */
4956 *PaletteNumber
= This
->currentPalette
;
4957 TRACE("(%p) : returning %u\n", This
, *PaletteNumber
);
4961 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice
*iface
, BOOL bSoftware
) {
4962 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4966 FIXME("(%p) : stub\n", This
);
4970 This
->softwareVertexProcessing
= bSoftware
;
4975 static BOOL WINAPI
IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice
*iface
) {
4976 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4980 FIXME("(%p) : stub\n", This
);
4983 return This
->softwareVertexProcessing
;
4986 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice
*iface
,
4987 UINT swapchain_idx
, WINED3DRASTER_STATUS
*raster_status
)
4989 IWineD3DSwapChain
*swapchain
;
4992 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
4993 iface
, swapchain_idx
, raster_status
);
4995 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, swapchain_idx
, &swapchain
);
4998 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx
, hr
);
5002 hr
= IWineD3DSwapChain_GetRasterStatus(swapchain
, raster_status
);
5003 IWineD3DSwapChain_Release(swapchain
);
5006 WARN("Failed to get raster status, hr %#x.\n", hr
);
5013 static HRESULT WINAPI
IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice
*iface
, float nSegments
)
5016 if(nSegments
!= 0.0f
) {
5019 FIXME("iface %p, nSegments %.8e stub!\n", iface
, nSegments
);
5026 static float WINAPI
IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice
*iface
)
5031 FIXME("iface %p stub!\n", iface
);
5037 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice
*iface
, IWineD3DSurface
*pSourceSurface
, CONST RECT
* pSourceRect
, IWineD3DSurface
*pDestinationSurface
, CONST POINT
* pDestPoint
) {
5038 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5039 /** TODO: remove casts to IWineD3DSurfaceImpl
5040 * NOTE: move code to surface to accomplish this
5041 ****************************************/
5042 IWineD3DSurfaceImpl
*pSrcSurface
= (IWineD3DSurfaceImpl
*)pSourceSurface
;
5043 IWineD3DSurfaceImpl
*dst_impl
= (IWineD3DSurfaceImpl
*)pDestinationSurface
;
5044 int srcWidth
, srcHeight
;
5045 unsigned int srcSurfaceWidth
, srcSurfaceHeight
, destSurfaceWidth
, destSurfaceHeight
;
5046 WINED3DFORMAT destFormat
, srcFormat
;
5048 int srcLeft
, destLeft
, destTop
;
5049 WINED3DPOOL srcPool
, destPool
;
5051 int rowoffset
= 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5052 const struct GlPixelFormatDesc
*src_format_desc
, *dst_format_desc
;
5056 CONVERT_TYPES convert
= NO_CONVERSION
;
5057 struct wined3d_context
*context
;
5059 WINED3DSURFACE_DESC winedesc
;
5061 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This
, pSourceSurface
, pSourceRect
, pDestinationSurface
, pDestPoint
);
5063 IWineD3DSurface_GetDesc(pSourceSurface
, &winedesc
);
5064 srcSurfaceWidth
= winedesc
.width
;
5065 srcSurfaceHeight
= winedesc
.height
;
5066 srcPool
= winedesc
.pool
;
5067 srcFormat
= winedesc
.format
;
5069 IWineD3DSurface_GetDesc(pDestinationSurface
, &winedesc
);
5070 destSurfaceWidth
= winedesc
.width
;
5071 destSurfaceHeight
= winedesc
.height
;
5072 destPool
= winedesc
.pool
;
5073 destFormat
= winedesc
.format
;
5074 destSize
= winedesc
.size
;
5076 if(srcPool
!= WINED3DPOOL_SYSTEMMEM
|| destPool
!= WINED3DPOOL_DEFAULT
){
5077 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface
, pDestinationSurface
);
5078 return WINED3DERR_INVALIDCALL
;
5081 /* This call loads the opengl surface directly, instead of copying the surface to the
5082 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5083 * copy in sysmem and use regular surface loading.
5085 d3dfmt_get_conv(dst_impl
, FALSE
, TRUE
, &dummy
, &dummy
, &dummy
, &convert
, &bpp
, FALSE
);
5086 if(convert
!= NO_CONVERSION
) {
5087 return IWineD3DSurface_BltFast(pDestinationSurface
,
5088 pDestPoint
? pDestPoint
->x
: 0,
5089 pDestPoint
? pDestPoint
->y
: 0,
5090 pSourceSurface
, pSourceRect
, 0);
5093 if (destFormat
== WINED3DFMT_UNKNOWN
) {
5094 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This
);
5095 IWineD3DSurface_SetFormat(pDestinationSurface
, srcFormat
);
5097 /* Get the update surface description */
5098 IWineD3DSurface_GetDesc(pDestinationSurface
, &winedesc
);
5101 context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
5104 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
5105 checkGLcall("glActiveTextureARB");
5108 /* Make sure the surface is loaded and up to date */
5109 surface_internal_preload(pDestinationSurface
, SRGB_RGB
);
5110 IWineD3DSurface_BindTexture(pDestinationSurface
, FALSE
);
5112 src_format_desc
= ((IWineD3DSurfaceImpl
*)pSrcSurface
)->resource
.format_desc
;
5113 dst_format_desc
= dst_impl
->resource
.format_desc
;
5115 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5116 srcWidth
= pSourceRect
? pSourceRect
->right
- pSourceRect
->left
: srcSurfaceWidth
;
5117 srcHeight
= pSourceRect
? pSourceRect
->bottom
- pSourceRect
->top
: srcSurfaceHeight
;
5118 srcLeft
= pSourceRect
? pSourceRect
->left
: 0;
5119 destLeft
= pDestPoint
? pDestPoint
->x
: 0;
5120 destTop
= pDestPoint
? pDestPoint
->y
: 0;
5123 /* This function doesn't support compressed textures
5124 the pitch is just bytesPerPixel * width */
5125 if(srcWidth
!= srcSurfaceWidth
|| srcLeft
){
5126 rowoffset
= srcSurfaceWidth
* src_format_desc
->byte_count
;
5127 offset
+= srcLeft
* src_format_desc
->byte_count
;
5128 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5130 /* TODO DXT formats */
5132 if(pSourceRect
!= NULL
&& pSourceRect
->top
!= 0){
5133 offset
+= pSourceRect
->top
* srcSurfaceWidth
* src_format_desc
->byte_count
;
5135 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5136 This
, dst_impl
->texture_level
, destLeft
, destTop
, srcWidth
, srcHeight
, dst_format_desc
->glFormat
,
5137 dst_format_desc
->glType
, IWineD3DSurface_GetData(pSourceSurface
), offset
);
5140 if (IWineD3DSurface_GetData(pSourceSurface
) == NULL
) {
5142 /* need to lock the surface to get the data */
5143 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5148 /* TODO: Cube and volume support */
5150 /* not a whole row so we have to do it a line at a time */
5153 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5154 const unsigned char* data
=((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface
)) + offset
;
5156 for (j
= destTop
; j
< (srcHeight
+ destTop
); ++j
)
5158 glTexSubImage2D(dst_impl
->texture_target
, dst_impl
->texture_level
, destLeft
, j
,
5159 srcWidth
, 1, dst_format_desc
->glFormat
, dst_format_desc
->glType
,data
);
5163 } else { /* Full width, so just write out the whole texture */
5164 const unsigned char* data
= ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface
)) + offset
;
5166 if (dst_format_desc
->Flags
& WINED3DFMT_FLAG_COMPRESSED
)
5168 if (destSurfaceHeight
!= srcHeight
|| destSurfaceWidth
!= srcWidth
)
5170 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across. */
5171 FIXME("Updating part of a compressed texture is not supported.\n");
5173 if (destFormat
!= srcFormat
)
5175 FIXME("Updating mixed format compressed textures is not supported.\n");
5179 GL_EXTCALL(glCompressedTexImage2DARB(dst_impl
->texture_target
, dst_impl
->texture_level
,
5180 dst_format_desc
->glInternal
, srcWidth
, srcHeight
, 0, destSize
, data
));
5185 glTexSubImage2D(dst_impl
->texture_target
, dst_impl
->texture_level
, destLeft
, destTop
,
5186 srcWidth
, srcHeight
, dst_format_desc
->glFormat
, dst_format_desc
->glType
, data
);
5189 checkGLcall("glTexSubImage2D");
5192 context_release(context
);
5194 IWineD3DSurface_ModifyLocation(pDestinationSurface
, SFLAG_INTEXTURE
, TRUE
);
5195 sampler
= This
->rev_tex_unit_map
[0];
5196 if (sampler
!= WINED3D_UNMAPPED_STAGE
)
5198 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(sampler
));
5204 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice
*iface
, UINT Handle
, CONST
float* pNumSegs
, CONST WINED3DRECTPATCH_INFO
* pRectPatchInfo
) {
5205 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5206 struct WineD3DRectPatch
*patch
;
5207 GLenum old_primitive_type
;
5211 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This
, Handle
, pNumSegs
, pRectPatchInfo
);
5213 if(!(Handle
|| pRectPatchInfo
)) {
5214 /* TODO: Write a test for the return value, thus the FIXME */
5215 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5216 return WINED3DERR_INVALIDCALL
;
5220 i
= PATCHMAP_HASHFUNC(Handle
);
5222 LIST_FOR_EACH(e
, &This
->patches
[i
]) {
5223 patch
= LIST_ENTRY(e
, struct WineD3DRectPatch
, entry
);
5224 if(patch
->Handle
== Handle
) {
5231 TRACE("Patch does not exist. Creating a new one\n");
5232 patch
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*patch
));
5233 patch
->Handle
= Handle
;
5234 list_add_head(&This
->patches
[i
], &patch
->entry
);
5236 TRACE("Found existing patch %p\n", patch
);
5239 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5240 * attributes we have to tesselate, read back, and draw. This needs a patch
5241 * management structure instance. Create one.
5243 * A possible improvement is to check if a vertex shader is used, and if not directly
5246 FIXME("Drawing an uncached patch. This is slow\n");
5247 patch
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*patch
));
5250 if(pNumSegs
[0] != patch
->numSegs
[0] || pNumSegs
[1] != patch
->numSegs
[1] ||
5251 pNumSegs
[2] != patch
->numSegs
[2] || pNumSegs
[3] != patch
->numSegs
[3] ||
5252 (pRectPatchInfo
&& memcmp(pRectPatchInfo
, &patch
->RectPatchInfo
, sizeof(*pRectPatchInfo
)) != 0) ) {
5254 TRACE("Tesselation density or patch info changed, retesselating\n");
5256 if(pRectPatchInfo
) {
5257 patch
->RectPatchInfo
= *pRectPatchInfo
;
5259 patch
->numSegs
[0] = pNumSegs
[0];
5260 patch
->numSegs
[1] = pNumSegs
[1];
5261 patch
->numSegs
[2] = pNumSegs
[2];
5262 patch
->numSegs
[3] = pNumSegs
[3];
5264 hr
= tesselate_rectpatch(This
, patch
);
5266 WARN("Patch tesselation failed\n");
5268 /* Do not release the handle to store the params of the patch */
5270 HeapFree(GetProcessHeap(), 0, patch
);
5276 This
->currentPatch
= patch
;
5277 old_primitive_type
= This
->stateBlock
->gl_primitive_type
;
5278 This
->stateBlock
->gl_primitive_type
= GL_TRIANGLES
;
5279 IWineD3DDevice_DrawPrimitiveStrided(iface
, patch
->numSegs
[0] * patch
->numSegs
[1] * 2 * 3, &patch
->strided
);
5280 This
->stateBlock
->gl_primitive_type
= old_primitive_type
;
5281 This
->currentPatch
= NULL
;
5283 /* Destroy uncached patches */
5285 HeapFree(GetProcessHeap(), 0, patch
->mem
);
5286 HeapFree(GetProcessHeap(), 0, patch
);
5291 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice
*iface
,
5292 UINT handle
, const float *segment_count
, const WINED3DTRIPATCH_INFO
*patch_info
)
5294 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5295 iface
, handle
, segment_count
, patch_info
);
5300 static HRESULT WINAPI
IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice
*iface
, UINT Handle
) {
5301 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5303 struct WineD3DRectPatch
*patch
;
5305 TRACE("(%p) Handle(%d)\n", This
, Handle
);
5307 i
= PATCHMAP_HASHFUNC(Handle
);
5308 LIST_FOR_EACH(e
, &This
->patches
[i
]) {
5309 patch
= LIST_ENTRY(e
, struct WineD3DRectPatch
, entry
);
5310 if(patch
->Handle
== Handle
) {
5311 TRACE("Deleting patch %p\n", patch
);
5312 list_remove(&patch
->entry
);
5313 HeapFree(GetProcessHeap(), 0, patch
->mem
);
5314 HeapFree(GetProcessHeap(), 0, patch
);
5319 /* TODO: Write a test for the return value */
5320 FIXME("Attempt to destroy nonexistent patch\n");
5321 return WINED3DERR_INVALIDCALL
;
5324 static IWineD3DSwapChain
*get_swapchain(IWineD3DSurface
*target
) {
5326 IWineD3DSwapChain
*swapchain
;
5328 hr
= IWineD3DSurface_GetContainer(target
, &IID_IWineD3DSwapChain
, (void **)&swapchain
);
5329 if (SUCCEEDED(hr
)) {
5330 IWineD3DSwapChain_Release((IUnknown
*)swapchain
);
5337 static void color_fill_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*surface
,
5338 const WINED3DRECT
*rect
, const float color
[4])
5340 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5341 struct wined3d_context
*context
;
5343 if (!surface_is_offscreen(surface
))
5345 TRACE("Surface %p is onscreen\n", surface
);
5347 context
= context_acquire(This
, surface
, CTXUSAGE_RESOURCELOAD
);
5349 context_bind_fbo(context
, GL_FRAMEBUFFER
, NULL
);
5350 context_set_draw_buffer(context
, surface_get_gl_buffer(surface
));
5354 TRACE("Surface %p is offscreen\n", surface
);
5356 context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
5358 context_bind_fbo(context
, GL_FRAMEBUFFER
, &context
->dst_fbo
);
5359 context_attach_surface_fbo(context
, GL_FRAMEBUFFER
, 0, surface
);
5360 context_attach_depth_stencil_fbo(context
, GL_FRAMEBUFFER
, NULL
, FALSE
);
5364 glEnable(GL_SCISSOR_TEST
);
5365 if(surface_is_offscreen(surface
)) {
5366 glScissor(rect
->x1
, rect
->y1
, rect
->x2
- rect
->x1
, rect
->y2
- rect
->y1
);
5368 glScissor(rect
->x1
, ((IWineD3DSurfaceImpl
*)surface
)->currentDesc
.Height
- rect
->y2
,
5369 rect
->x2
- rect
->x1
, rect
->y2
- rect
->y1
);
5371 checkGLcall("glScissor");
5372 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SCISSORRECT
);
5374 glDisable(GL_SCISSOR_TEST
);
5376 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE
));
5378 glDisable(GL_BLEND
);
5379 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE
));
5381 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
5382 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE
));
5384 glClearColor(color
[0], color
[1], color
[2], color
[3]);
5385 glClear(GL_COLOR_BUFFER_BIT
);
5386 checkGLcall("glClear");
5389 context_release(context
);
5392 static inline DWORD
argb_to_fmt(DWORD color
, WINED3DFORMAT destfmt
) {
5393 unsigned int r
, g
, b
, a
;
5396 if (destfmt
== WINED3DFMT_B8G8R8A8_UNORM
5397 || destfmt
== WINED3DFMT_B8G8R8X8_UNORM
5398 || destfmt
== WINED3DFMT_B8G8R8_UNORM
)
5401 TRACE("Converting color %08x to format %s\n", color
, debug_d3dformat(destfmt
));
5403 a
= (color
& 0xff000000) >> 24;
5404 r
= (color
& 0x00ff0000) >> 16;
5405 g
= (color
& 0x0000ff00) >> 8;
5406 b
= (color
& 0x000000ff) >> 0;
5410 case WINED3DFMT_B5G6R5_UNORM
:
5411 if(r
== 0xff && g
== 0xff && b
== 0xff) return 0xffff;
5418 TRACE("Returning %08x\n", ret
);
5421 case WINED3DFMT_B5G5R5X1_UNORM
:
5422 case WINED3DFMT_B5G5R5A1_UNORM
:
5431 TRACE("Returning %08x\n", ret
);
5434 case WINED3DFMT_A8_UNORM
:
5435 TRACE("Returning %08x\n", a
);
5438 case WINED3DFMT_B4G4R4X4_UNORM
:
5439 case WINED3DFMT_B4G4R4A4_UNORM
:
5448 TRACE("Returning %08x\n", ret
);
5451 case WINED3DFMT_B2G3R3_UNORM
:
5458 TRACE("Returning %08x\n", ret
);
5461 case WINED3DFMT_R8G8B8X8_UNORM
:
5462 case WINED3DFMT_R8G8B8A8_UNORM
:
5467 TRACE("Returning %08x\n", ret
);
5470 case WINED3DFMT_B10G10R10A2_UNORM
:
5472 r
= (r
* 1024) / 256;
5473 g
= (g
* 1024) / 256;
5474 b
= (b
* 1024) / 256;
5479 TRACE("Returning %08x\n", ret
);
5482 case WINED3DFMT_R10G10B10A2_UNORM
:
5484 r
= (r
* 1024) / 256;
5485 g
= (g
* 1024) / 256;
5486 b
= (b
* 1024) / 256;
5491 TRACE("Returning %08x\n", ret
);
5495 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt
));
5500 static HRESULT WINAPI
IWineD3DDeviceImpl_ColorFill(IWineD3DDevice
*iface
,
5501 IWineD3DSurface
*pSurface
, const WINED3DRECT
*pRect
, WINED3DCOLOR color
)
5503 IWineD3DSurfaceImpl
*surface
= (IWineD3DSurfaceImpl
*) pSurface
;
5506 TRACE("iface %p, surface %p, rect %p, color 0x%08x.\n", iface
, pSurface
, pRect
, color
);
5508 if (surface
->resource
.pool
!= WINED3DPOOL_DEFAULT
&& surface
->resource
.pool
!= WINED3DPOOL_SYSTEMMEM
) {
5509 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5510 return WINED3DERR_INVALIDCALL
;
5513 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
5514 const float c
[4] = {D3DCOLOR_R(color
), D3DCOLOR_G(color
), D3DCOLOR_B(color
), D3DCOLOR_A(color
)};
5515 color_fill_fbo(iface
, pSurface
, pRect
, c
);
5518 /* Just forward this to the DirectDraw blitting engine */
5519 memset(&BltFx
, 0, sizeof(BltFx
));
5520 BltFx
.dwSize
= sizeof(BltFx
);
5521 BltFx
.u5
.dwFillColor
= argb_to_fmt(color
, surface
->resource
.format_desc
->format
);
5522 return IWineD3DSurface_Blt(pSurface
, (const RECT
*)pRect
, NULL
, NULL
,
5523 WINEDDBLT_COLORFILL
, &BltFx
, WINED3DTEXF_POINT
);
5527 static void WINAPI
IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice
*iface
,
5528 IWineD3DRendertargetView
*rendertarget_view
, const float color
[4])
5530 IWineD3DResource
*resource
;
5531 IWineD3DSurface
*surface
;
5534 hr
= IWineD3DRendertargetView_GetResource(rendertarget_view
, &resource
);
5537 ERR("Failed to get resource, hr %#x\n", hr
);
5541 if (IWineD3DResource_GetType(resource
) != WINED3DRTYPE_SURFACE
)
5543 FIXME("Only supported on surface resources\n");
5544 IWineD3DResource_Release(resource
);
5548 surface
= (IWineD3DSurface
*)resource
;
5550 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
)
5552 color_fill_fbo(iface
, surface
, NULL
, color
);
5559 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5561 c
= ((DWORD
)(color
[2] * 255.0f
));
5562 c
|= ((DWORD
)(color
[1] * 255.0f
)) << 8;
5563 c
|= ((DWORD
)(color
[0] * 255.0f
)) << 16;
5564 c
|= ((DWORD
)(color
[3] * 255.0f
)) << 24;
5566 /* Just forward this to the DirectDraw blitting engine */
5567 memset(&BltFx
, 0, sizeof(BltFx
));
5568 BltFx
.dwSize
= sizeof(BltFx
);
5569 BltFx
.u5
.dwFillColor
= argb_to_fmt(c
, ((IWineD3DSurfaceImpl
*)surface
)->resource
.format_desc
->format
);
5570 hr
= IWineD3DSurface_Blt(surface
, NULL
, NULL
, NULL
, WINEDDBLT_COLORFILL
, &BltFx
, WINED3DTEXF_POINT
);
5573 ERR("Blt failed, hr %#x\n", hr
);
5577 IWineD3DResource_Release(resource
);
5580 /* rendertarget and depth stencil functions */
5581 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice
* iface
,DWORD RenderTargetIndex
, IWineD3DSurface
**ppRenderTarget
) {
5582 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5584 if (RenderTargetIndex
>= This
->adapter
->gl_info
.limits
.buffers
)
5586 ERR("(%p) : Only %d render targets are supported.\n",
5587 This
, This
->adapter
->gl_info
.limits
.buffers
);
5588 return WINED3DERR_INVALIDCALL
;
5591 *ppRenderTarget
= This
->render_targets
[RenderTargetIndex
];
5592 TRACE("(%p) : RenderTarget %d Index returning %p\n", This
, RenderTargetIndex
, *ppRenderTarget
);
5593 /* Note inc ref on returned surface */
5594 if(*ppRenderTarget
!= NULL
)
5595 IWineD3DSurface_AddRef(*ppRenderTarget
);
5599 static HRESULT WINAPI
IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice
*iface
,
5600 IWineD3DSurface
*Front
, IWineD3DSurface
*Back
)
5602 IWineD3DSurfaceImpl
*FrontImpl
= (IWineD3DSurfaceImpl
*) Front
;
5603 IWineD3DSurfaceImpl
*BackImpl
= (IWineD3DSurfaceImpl
*) Back
;
5604 IWineD3DSwapChainImpl
*Swapchain
;
5607 TRACE("iface %p, front %p, back %p.\n", iface
, Front
, Back
);
5609 hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**) &Swapchain
);
5610 if(hr
!= WINED3D_OK
) {
5611 ERR("Can't get the swapchain\n");
5615 /* Make sure to release the swapchain */
5616 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) Swapchain
);
5618 if(FrontImpl
&& !(FrontImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) ) {
5619 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5620 return WINED3DERR_INVALIDCALL
;
5622 else if(BackImpl
&& !(BackImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)) {
5623 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5624 return WINED3DERR_INVALIDCALL
;
5627 if(Swapchain
->frontBuffer
!= Front
) {
5628 TRACE("Changing the front buffer from %p to %p\n", Swapchain
->frontBuffer
, Front
);
5630 if(Swapchain
->frontBuffer
)
5632 IWineD3DSurface_SetContainer(Swapchain
->frontBuffer
, NULL
);
5633 ((IWineD3DSurfaceImpl
*)Swapchain
->frontBuffer
)->Flags
&= ~SFLAG_SWAPCHAIN
;
5635 Swapchain
->frontBuffer
= Front
;
5637 if(Swapchain
->frontBuffer
) {
5638 IWineD3DSurface_SetContainer(Swapchain
->frontBuffer
, (IWineD3DBase
*) Swapchain
);
5639 ((IWineD3DSurfaceImpl
*)Swapchain
->frontBuffer
)->Flags
|= SFLAG_SWAPCHAIN
;
5643 if(Back
&& !Swapchain
->backBuffer
) {
5644 /* We need memory for the back buffer array - only one back buffer this way */
5645 Swapchain
->backBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DSurface
*));
5646 if(!Swapchain
->backBuffer
) {
5647 ERR("Out of memory\n");
5648 return E_OUTOFMEMORY
;
5652 if(Swapchain
->backBuffer
[0] != Back
) {
5653 TRACE("Changing the back buffer from %p to %p\n", Swapchain
->backBuffer
, Back
);
5655 /* What to do about the context here in the case of multithreading? Not sure.
5656 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5658 WARN("No active context?\n");
5661 if(!Swapchain
->backBuffer
[0]) {
5662 /* GL was told to draw to the front buffer at creation,
5665 glDrawBuffer(GL_BACK
);
5666 checkGLcall("glDrawBuffer(GL_BACK)");
5667 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5668 Swapchain
->presentParms
.BackBufferCount
= 1;
5670 /* That makes problems - disable for now */
5671 /* glDrawBuffer(GL_FRONT); */
5672 checkGLcall("glDrawBuffer(GL_FRONT)");
5673 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5674 Swapchain
->presentParms
.BackBufferCount
= 0;
5678 if(Swapchain
->backBuffer
[0])
5680 IWineD3DSurface_SetContainer(Swapchain
->backBuffer
[0], NULL
);
5681 ((IWineD3DSurfaceImpl
*)Swapchain
->backBuffer
[0])->Flags
&= ~SFLAG_SWAPCHAIN
;
5683 Swapchain
->backBuffer
[0] = Back
;
5685 if(Swapchain
->backBuffer
[0]) {
5686 IWineD3DSurface_SetContainer(Swapchain
->backBuffer
[0], (IWineD3DBase
*) Swapchain
);
5687 ((IWineD3DSurfaceImpl
*)Swapchain
->backBuffer
[0])->Flags
|= SFLAG_SWAPCHAIN
;
5689 HeapFree(GetProcessHeap(), 0, Swapchain
->backBuffer
);
5690 Swapchain
->backBuffer
= NULL
;
5698 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice
* iface
, IWineD3DSurface
**ppZStencilSurface
) {
5699 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5700 *ppZStencilSurface
= This
->stencilBufferTarget
;
5701 TRACE("(%p) : zStencilSurface returning %p\n", This
, *ppZStencilSurface
);
5703 if(*ppZStencilSurface
!= NULL
) {
5704 /* Note inc ref on returned surface */
5705 IWineD3DSurface_AddRef(*ppZStencilSurface
);
5708 return WINED3DERR_NOTFOUND
;
5712 void stretch_rect_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*src_surface
, WINED3DRECT
*src_rect
,
5713 IWineD3DSurface
*dst_surface
, WINED3DRECT
*dst_rect
, const WINED3DTEXTUREFILTERTYPE filter
, BOOL flip
)
5715 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5716 GLbitfield mask
= GL_COLOR_BUFFER_BIT
; /* TODO: Support blitting depth/stencil surfaces */
5717 IWineD3DSwapChain
*src_swapchain
, *dst_swapchain
;
5718 const struct wined3d_gl_info
*gl_info
;
5719 struct wined3d_context
*context
;
5721 POINT offset
= {0, 0};
5723 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5724 This
, src_surface
, src_rect
, dst_surface
, dst_rect
, debug_d3dtexturefiltertype(filter
), filter
, flip
);
5725 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
);
5726 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect
->x1
, dst_rect
->y1
, dst_rect
->x2
, dst_rect
->y2
);
5729 case WINED3DTEXF_LINEAR
:
5730 gl_filter
= GL_LINEAR
;
5734 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter
), filter
);
5735 case WINED3DTEXF_NONE
:
5736 case WINED3DTEXF_POINT
:
5737 gl_filter
= GL_NEAREST
;
5741 /* Attach src surface to src fbo */
5742 src_swapchain
= get_swapchain(src_surface
);
5743 dst_swapchain
= get_swapchain(dst_surface
);
5745 if (src_swapchain
) context
= context_acquire(This
, src_surface
, CTXUSAGE_RESOURCELOAD
);
5746 else if (dst_swapchain
) context
= context_acquire(This
, dst_surface
, CTXUSAGE_RESOURCELOAD
);
5747 else context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
5749 gl_info
= context
->gl_info
;
5751 if (!surface_is_offscreen(src_surface
))
5753 GLenum buffer
= surface_get_gl_buffer(src_surface
);
5755 TRACE("Source surface %p is onscreen\n", src_surface
);
5756 /* Make sure the drawable is up to date. In the offscreen case
5757 * attach_surface_fbo() implicitly takes care of this. */
5758 IWineD3DSurface_LoadLocation(src_surface
, SFLAG_INDRAWABLE
, NULL
);
5760 if(buffer
== GL_FRONT
) {
5763 ClientToScreen(((IWineD3DSwapChainImpl
*)src_swapchain
)->win_handle
, &offset
);
5764 GetClientRect(((IWineD3DSwapChainImpl
*)src_swapchain
)->win_handle
, &windowsize
);
5765 h
= windowsize
.bottom
- windowsize
.top
;
5766 src_rect
->x1
-= offset
.x
; src_rect
->x2
-=offset
.x
;
5767 src_rect
->y1
= offset
.y
+ h
- src_rect
->y1
;
5768 src_rect
->y2
= offset
.y
+ h
- src_rect
->y2
;
5770 src_rect
->y1
= ((IWineD3DSurfaceImpl
*)src_surface
)->currentDesc
.Height
- src_rect
->y1
;
5771 src_rect
->y2
= ((IWineD3DSurfaceImpl
*)src_surface
)->currentDesc
.Height
- src_rect
->y2
;
5775 context_bind_fbo(context
, GL_READ_FRAMEBUFFER
, NULL
);
5776 glReadBuffer(buffer
);
5777 checkGLcall("glReadBuffer()");
5779 TRACE("Source surface %p is offscreen\n", src_surface
);
5781 context_bind_fbo(context
, GL_READ_FRAMEBUFFER
, &context
->src_fbo
);
5782 context_attach_surface_fbo(context
, GL_READ_FRAMEBUFFER
, 0, src_surface
);
5783 glReadBuffer(GL_COLOR_ATTACHMENT0
);
5784 checkGLcall("glReadBuffer()");
5785 context_attach_depth_stencil_fbo(context
, GL_READ_FRAMEBUFFER
, NULL
, FALSE
);
5789 /* Attach dst surface to dst fbo */
5790 if (!surface_is_offscreen(dst_surface
))
5792 GLenum buffer
= surface_get_gl_buffer(dst_surface
);
5794 TRACE("Destination surface %p is onscreen\n", dst_surface
);
5795 /* Make sure the drawable is up to date. In the offscreen case
5796 * attach_surface_fbo() implicitly takes care of this. */
5797 IWineD3DSurface_LoadLocation(dst_surface
, SFLAG_INDRAWABLE
, NULL
);
5799 if(buffer
== GL_FRONT
) {
5802 ClientToScreen(((IWineD3DSwapChainImpl
*)dst_swapchain
)->win_handle
, &offset
);
5803 GetClientRect(((IWineD3DSwapChainImpl
*)dst_swapchain
)->win_handle
, &windowsize
);
5804 h
= windowsize
.bottom
- windowsize
.top
;
5805 dst_rect
->x1
-= offset
.x
; dst_rect
->x2
-=offset
.x
;
5806 dst_rect
->y1
= offset
.y
+ h
- dst_rect
->y1
;
5807 dst_rect
->y2
= offset
.y
+ h
- dst_rect
->y2
;
5809 /* Screen coords = window coords, surface height = window height */
5810 dst_rect
->y1
= ((IWineD3DSurfaceImpl
*)dst_surface
)->currentDesc
.Height
- dst_rect
->y1
;
5811 dst_rect
->y2
= ((IWineD3DSurfaceImpl
*)dst_surface
)->currentDesc
.Height
- dst_rect
->y2
;
5815 context_bind_fbo(context
, GL_DRAW_FRAMEBUFFER
, NULL
);
5816 context_set_draw_buffer(context
, buffer
);
5820 TRACE("Destination surface %p is offscreen\n", dst_surface
);
5823 context_bind_fbo(context
, GL_DRAW_FRAMEBUFFER
, &context
->dst_fbo
);
5824 context_attach_surface_fbo(context
, GL_DRAW_FRAMEBUFFER
, 0, dst_surface
);
5825 context_set_draw_buffer(context
, GL_COLOR_ATTACHMENT0
);
5826 context_attach_depth_stencil_fbo(context
, GL_DRAW_FRAMEBUFFER
, NULL
, FALSE
);
5828 glDisable(GL_SCISSOR_TEST
);
5829 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE
));
5832 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
,
5833 dst_rect
->x1
, dst_rect
->y2
, dst_rect
->x2
, dst_rect
->y1
, mask
, gl_filter
);
5834 checkGLcall("glBlitFramebuffer()");
5836 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
,
5837 dst_rect
->x1
, dst_rect
->y1
, dst_rect
->x2
, dst_rect
->y2
, mask
, gl_filter
);
5838 checkGLcall("glBlitFramebuffer()");
5842 context_release(context
);
5844 IWineD3DSurface_ModifyLocation(dst_surface
, SFLAG_INDRAWABLE
, TRUE
);
5847 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice
*iface
, DWORD RenderTargetIndex
, IWineD3DSurface
*pRenderTarget
,
5848 BOOL set_viewport
) {
5849 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5851 TRACE("(%p) : Setting rendertarget %d to %p\n", This
, RenderTargetIndex
, pRenderTarget
);
5853 if (RenderTargetIndex
>= This
->adapter
->gl_info
.limits
.buffers
)
5855 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
5856 This
, RenderTargetIndex
, This
->adapter
->gl_info
.limits
.buffers
);
5857 return WINED3DERR_INVALIDCALL
;
5860 /* MSDN says that null disables the render target
5861 but a device must always be associated with a render target
5862 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5864 if (RenderTargetIndex
== 0 && pRenderTarget
== NULL
) {
5865 FIXME("Trying to set render target 0 to NULL\n");
5866 return WINED3DERR_INVALIDCALL
;
5868 if (pRenderTarget
&& !(((IWineD3DSurfaceImpl
*)pRenderTarget
)->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)) {
5869 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
);
5870 return WINED3DERR_INVALIDCALL
;
5873 /* If we are trying to set what we already have, don't bother */
5874 if (pRenderTarget
== This
->render_targets
[RenderTargetIndex
]) {
5875 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5878 if(pRenderTarget
) IWineD3DSurface_AddRef(pRenderTarget
);
5879 if(This
->render_targets
[RenderTargetIndex
]) IWineD3DSurface_Release(This
->render_targets
[RenderTargetIndex
]);
5880 This
->render_targets
[RenderTargetIndex
] = pRenderTarget
;
5882 /* Render target 0 is special */
5883 if(RenderTargetIndex
== 0 && set_viewport
) {
5884 /* Finally, reset the viewport and scissor rect as the MSDN states.
5885 * Tests show that stateblock recording is ignored, the change goes
5886 * directly into the primary stateblock.
5888 This
->stateBlock
->viewport
.Height
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Height
;
5889 This
->stateBlock
->viewport
.Width
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Width
;
5890 This
->stateBlock
->viewport
.X
= 0;
5891 This
->stateBlock
->viewport
.Y
= 0;
5892 This
->stateBlock
->viewport
.MaxZ
= 1.0f
;
5893 This
->stateBlock
->viewport
.MinZ
= 0.0f
;
5894 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VIEWPORT
);
5896 This
->stateBlock
->scissorRect
.top
= 0;
5897 This
->stateBlock
->scissorRect
.left
= 0;
5898 This
->stateBlock
->scissorRect
.right
= This
->stateBlock
->viewport
.Width
;
5899 This
->stateBlock
->scissorRect
.bottom
= This
->stateBlock
->viewport
.Height
;
5900 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SCISSORRECT
);
5905 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice
*iface
, IWineD3DSurface
*pNewZStencil
) {
5906 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5907 HRESULT hr
= WINED3D_OK
;
5908 IWineD3DSurface
*tmp
;
5910 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This
, This
->stencilBufferTarget
, pNewZStencil
);
5912 if (pNewZStencil
== This
->stencilBufferTarget
) {
5913 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5915 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
5916 * depending on the renter target implementation being used.
5917 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5918 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5919 * stencil buffer and incur an extra memory overhead
5920 ******************************************************/
5922 if (This
->stencilBufferTarget
) {
5923 if (((IWineD3DSwapChainImpl
*)This
->swapchains
[0])->presentParms
.Flags
& WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5924 || ((IWineD3DSurfaceImpl
*)This
->stencilBufferTarget
)->Flags
& SFLAG_DISCARD
) {
5925 surface_modify_ds_location(This
->stencilBufferTarget
, SFLAG_DS_DISCARDED
);
5927 struct wined3d_context
*context
= context_acquire(This
, This
->render_targets
[0], CTXUSAGE_RESOURCELOAD
);
5928 surface_load_ds_location(This
->stencilBufferTarget
, context
, SFLAG_DS_OFFSCREEN
);
5929 surface_modify_ds_location(This
->stencilBufferTarget
, SFLAG_DS_OFFSCREEN
);
5930 context_release(context
);
5934 tmp
= This
->stencilBufferTarget
;
5935 This
->stencilBufferTarget
= pNewZStencil
;
5936 /* should we be calling the parent or the wined3d surface? */
5937 if (NULL
!= This
->stencilBufferTarget
) IWineD3DSurface_AddRef(This
->stencilBufferTarget
);
5938 if (NULL
!= tmp
) IWineD3DSurface_Release(tmp
);
5941 if((!tmp
&& pNewZStencil
) || (!pNewZStencil
&& tmp
)) {
5942 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5943 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ZENABLE
));
5944 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_STENCILENABLE
));
5945 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_STENCILWRITEMASK
));
5952 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice
* iface
, UINT XHotSpot
,
5953 UINT YHotSpot
, IWineD3DSurface
*pCursorBitmap
) {
5954 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5955 /* TODO: the use of Impl is deprecated. */
5956 IWineD3DSurfaceImpl
* pSur
= (IWineD3DSurfaceImpl
*) pCursorBitmap
;
5957 WINED3DLOCKED_RECT lockedRect
;
5959 TRACE("(%p) : Spot Pos(%u,%u)\n", This
, XHotSpot
, YHotSpot
);
5961 /* some basic validation checks */
5962 if(This
->cursorTexture
) {
5963 struct wined3d_context
*context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
5965 glDeleteTextures(1, &This
->cursorTexture
);
5967 context_release(context
);
5968 This
->cursorTexture
= 0;
5971 if ( (pSur
->currentDesc
.Width
== 32) && (pSur
->currentDesc
.Height
== 32) )
5972 This
->haveHardwareCursor
= TRUE
;
5974 This
->haveHardwareCursor
= FALSE
;
5977 WINED3DLOCKED_RECT rect
;
5979 /* MSDN: Cursor must be A8R8G8B8 */
5980 if (pSur
->resource
.format_desc
->format
!= WINED3DFMT_B8G8R8A8_UNORM
)
5982 ERR("(%p) : surface(%p) has an invalid format\n", This
, pCursorBitmap
);
5983 return WINED3DERR_INVALIDCALL
;
5986 /* MSDN: Cursor must be smaller than the display mode */
5987 if(pSur
->currentDesc
.Width
> This
->ddraw_width
||
5988 pSur
->currentDesc
.Height
> This
->ddraw_height
) {
5989 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
);
5990 return WINED3DERR_INVALIDCALL
;
5993 if (!This
->haveHardwareCursor
) {
5994 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5996 /* Do not store the surface's pointer because the application may
5997 * release it after setting the cursor image. Windows doesn't
5998 * addref the set surface, so we can't do this either without
5999 * creating circular refcount dependencies. Copy out the gl texture
6002 This
->cursorWidth
= pSur
->currentDesc
.Width
;
6003 This
->cursorHeight
= pSur
->currentDesc
.Height
;
6004 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap
, &rect
, NULL
, WINED3DLOCK_READONLY
)))
6006 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
6007 const struct GlPixelFormatDesc
*glDesc
= getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM
, gl_info
);
6008 struct wined3d_context
*context
;
6009 char *mem
, *bits
= rect
.pBits
;
6010 GLint intfmt
= glDesc
->glInternal
;
6011 GLint format
= glDesc
->glFormat
;
6012 GLint type
= glDesc
->glType
;
6013 INT height
= This
->cursorHeight
;
6014 INT width
= This
->cursorWidth
;
6015 INT bpp
= glDesc
->byte_count
;
6019 /* Reformat the texture memory (pitch and width can be
6021 mem
= HeapAlloc(GetProcessHeap(), 0, width
* height
* bpp
);
6022 for(i
= 0; i
< height
; i
++)
6023 memcpy(&mem
[width
* bpp
* i
], &bits
[rect
.Pitch
* i
], width
* bpp
);
6024 IWineD3DSurface_UnlockRect(pCursorBitmap
);
6026 context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
6030 if (gl_info
->supported
[APPLE_CLIENT_STORAGE
])
6032 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
6033 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6036 /* Make sure that a proper texture unit is selected */
6037 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
6038 checkGLcall("glActiveTextureARB");
6039 sampler
= This
->rev_tex_unit_map
[0];
6040 if (sampler
!= WINED3D_UNMAPPED_STAGE
)
6042 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(sampler
));
6044 /* Create a new cursor texture */
6045 glGenTextures(1, &This
->cursorTexture
);
6046 checkGLcall("glGenTextures");
6047 glBindTexture(GL_TEXTURE_2D
, This
->cursorTexture
);
6048 checkGLcall("glBindTexture");
6049 /* Copy the bitmap memory into the cursor texture */
6050 glTexImage2D(GL_TEXTURE_2D
, 0, intfmt
, width
, height
, 0, format
, type
, mem
);
6051 HeapFree(GetProcessHeap(), 0, mem
);
6052 checkGLcall("glTexImage2D");
6054 if (gl_info
->supported
[APPLE_CLIENT_STORAGE
])
6056 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
6057 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6062 context_release(context
);
6066 FIXME("A cursor texture was not returned.\n");
6067 This
->cursorTexture
= 0;
6072 /* Draw a hardware cursor */
6073 ICONINFO cursorInfo
;
6075 /* Create and clear maskBits because it is not needed for
6076 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6078 DWORD
*maskBits
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
6079 (pSur
->currentDesc
.Width
* pSur
->currentDesc
.Height
/ 8));
6080 IWineD3DSurface_LockRect(pCursorBitmap
, &lockedRect
, NULL
,
6081 WINED3DLOCK_NO_DIRTY_UPDATE
|
6082 WINED3DLOCK_READONLY
6084 TRACE("width: %i height: %i\n", pSur
->currentDesc
.Width
,
6085 pSur
->currentDesc
.Height
);
6087 cursorInfo
.fIcon
= FALSE
;
6088 cursorInfo
.xHotspot
= XHotSpot
;
6089 cursorInfo
.yHotspot
= YHotSpot
;
6090 cursorInfo
.hbmMask
= CreateBitmap(pSur
->currentDesc
.Width
, pSur
->currentDesc
.Height
,
6092 cursorInfo
.hbmColor
= CreateBitmap(pSur
->currentDesc
.Width
, pSur
->currentDesc
.Height
,
6093 1, 32, lockedRect
.pBits
);
6094 IWineD3DSurface_UnlockRect(pCursorBitmap
);
6095 /* Create our cursor and clean up. */
6096 cursor
= CreateIconIndirect(&cursorInfo
);
6098 if (cursorInfo
.hbmMask
) DeleteObject(cursorInfo
.hbmMask
);
6099 if (cursorInfo
.hbmColor
) DeleteObject(cursorInfo
.hbmColor
);
6100 if (This
->hardwareCursor
) DestroyCursor(This
->hardwareCursor
);
6101 This
->hardwareCursor
= cursor
;
6102 HeapFree(GetProcessHeap(), 0, maskBits
);
6106 This
->xHotSpot
= XHotSpot
;
6107 This
->yHotSpot
= YHotSpot
;
6111 static void WINAPI
IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice
* iface
, int XScreenSpace
, int YScreenSpace
, DWORD Flags
) {
6112 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6113 TRACE("(%p) : SetPos to (%u,%u)\n", This
, XScreenSpace
, YScreenSpace
);
6115 This
->xScreenSpace
= XScreenSpace
;
6116 This
->yScreenSpace
= YScreenSpace
;
6122 static BOOL WINAPI
IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice
* iface
, BOOL bShow
) {
6123 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6124 BOOL oldVisible
= This
->bCursorVisible
;
6127 TRACE("(%p) : visible(%d)\n", This
, bShow
);
6130 * When ShowCursor is first called it should make the cursor appear at the OS's last
6131 * known cursor position. Because of this, some applications just repetitively call
6132 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6135 This
->xScreenSpace
= pt
.x
;
6136 This
->yScreenSpace
= pt
.y
;
6138 if (This
->haveHardwareCursor
) {
6139 This
->bCursorVisible
= bShow
;
6141 SetCursor(This
->hardwareCursor
);
6147 if (This
->cursorTexture
)
6148 This
->bCursorVisible
= bShow
;
6154 static HRESULT WINAPI
evict_managed_resource(IWineD3DResource
*resource
, void *data
) {
6155 TRACE("checking resource %p for eviction\n", resource
);
6156 if(((IWineD3DResourceImpl
*) resource
)->resource
.pool
== WINED3DPOOL_MANAGED
) {
6157 TRACE("Evicting %p\n", resource
);
6158 IWineD3DResource_UnLoad(resource
);
6160 IWineD3DResource_Release(resource
);
6164 static HRESULT WINAPI
IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice
*iface
)
6166 TRACE("iface %p.\n", iface
);
6168 IWineD3DDevice_EnumResources(iface
, evict_managed_resource
, NULL
);
6172 static HRESULT
updateSurfaceDesc(IWineD3DSurfaceImpl
*surface
, const WINED3DPRESENT_PARAMETERS
* pPresentationParameters
)
6174 IWineD3DDeviceImpl
*device
= surface
->resource
.device
;
6175 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
6177 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6178 if(surface
->Flags
& SFLAG_DIBSECTION
) {
6179 /* Release the DC */
6180 SelectObject(surface
->hDC
, surface
->dib
.holdbitmap
);
6181 DeleteDC(surface
->hDC
);
6182 /* Release the DIB section */
6183 DeleteObject(surface
->dib
.DIBsection
);
6184 surface
->dib
.bitmap_data
= NULL
;
6185 surface
->resource
.allocatedMemory
= NULL
;
6186 surface
->Flags
&= ~SFLAG_DIBSECTION
;
6188 surface
->currentDesc
.Width
= pPresentationParameters
->BackBufferWidth
;
6189 surface
->currentDesc
.Height
= pPresentationParameters
->BackBufferHeight
;
6190 if (gl_info
->supported
[ARB_TEXTURE_NON_POWER_OF_TWO
] || gl_info
->supported
[ARB_TEXTURE_RECTANGLE
]
6191 || gl_info
->supported
[WINE_NORMALIZED_TEXRECT
])
6193 surface
->pow2Width
= pPresentationParameters
->BackBufferWidth
;
6194 surface
->pow2Height
= pPresentationParameters
->BackBufferHeight
;
6196 surface
->pow2Width
= surface
->pow2Height
= 1;
6197 while (surface
->pow2Width
< pPresentationParameters
->BackBufferWidth
) surface
->pow2Width
<<= 1;
6198 while (surface
->pow2Height
< pPresentationParameters
->BackBufferHeight
) surface
->pow2Height
<<= 1;
6200 surface
->glRect
.left
= 0;
6201 surface
->glRect
.top
= 0;
6202 surface
->glRect
.right
= surface
->pow2Width
;
6203 surface
->glRect
.bottom
= surface
->pow2Height
;
6205 if (surface
->texture_name
)
6207 struct wined3d_context
*context
= context_acquire(device
, NULL
, CTXUSAGE_RESOURCELOAD
);
6209 glDeleteTextures(1, &surface
->texture_name
);
6211 context_release(context
);
6212 surface
->texture_name
= 0;
6213 surface
->Flags
&= ~SFLAG_CLIENT
;
6215 if(surface
->pow2Width
!= pPresentationParameters
->BackBufferWidth
||
6216 surface
->pow2Height
!= pPresentationParameters
->BackBufferHeight
) {
6217 surface
->Flags
|= SFLAG_NONPOW2
;
6219 surface
->Flags
&= ~SFLAG_NONPOW2
;
6221 HeapFree(GetProcessHeap(), 0, surface
->resource
.heapMemory
);
6222 surface
->resource
.allocatedMemory
= NULL
;
6223 surface
->resource
.heapMemory
= NULL
;
6224 surface
->resource
.size
= IWineD3DSurface_GetPitch((IWineD3DSurface
*) surface
) * surface
->pow2Width
;
6226 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6228 if(!surface_init_sysmem((IWineD3DSurface
*) surface
))
6230 return E_OUTOFMEMORY
;
6235 static HRESULT WINAPI
reset_unload_resources(IWineD3DResource
*resource
, void *data
) {
6236 TRACE("Unloading resource %p\n", resource
);
6237 IWineD3DResource_UnLoad(resource
);
6238 IWineD3DResource_Release(resource
);
6242 static BOOL
is_display_mode_supported(IWineD3DDeviceImpl
*This
, const WINED3DPRESENT_PARAMETERS
*pp
)
6245 WINED3DDISPLAYMODE m
;
6248 /* All Windowed modes are supported, as is leaving the current mode */
6249 if(pp
->Windowed
) return TRUE
;
6250 if(!pp
->BackBufferWidth
) return TRUE
;
6251 if(!pp
->BackBufferHeight
) return TRUE
;
6253 count
= IWineD3D_GetAdapterModeCount(This
->wined3d
, This
->adapter
->ordinal
, WINED3DFMT_UNKNOWN
);
6254 for(i
= 0; i
< count
; i
++) {
6255 memset(&m
, 0, sizeof(m
));
6256 hr
= IWineD3D_EnumAdapterModes(This
->wined3d
, This
->adapter
->ordinal
, WINED3DFMT_UNKNOWN
, i
, &m
);
6258 ERR("EnumAdapterModes failed\n");
6260 if(m
.Width
== pp
->BackBufferWidth
&& m
.Height
== pp
->BackBufferHeight
) {
6261 /* Mode found, it is supported */
6265 /* Mode not found -> not supported */
6269 void delete_opengl_contexts(IWineD3DDevice
*iface
, IWineD3DSwapChain
*swapchain_iface
) {
6270 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6271 IWineD3DSwapChainImpl
*swapchain
= (IWineD3DSwapChainImpl
*) swapchain_iface
;
6272 const struct wined3d_gl_info
*gl_info
;
6273 struct wined3d_context
*context
;
6274 IWineD3DBaseShaderImpl
*shader
;
6276 context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
6277 gl_info
= context
->gl_info
;
6279 IWineD3DDevice_EnumResources(iface
, reset_unload_resources
, NULL
);
6280 LIST_FOR_EACH_ENTRY(shader
, &This
->shaders
, IWineD3DBaseShaderImpl
, baseShader
.shader_list_entry
) {
6281 This
->shader_backend
->shader_destroy((IWineD3DBaseShader
*) shader
);
6285 if(This
->depth_blt_texture
) {
6286 glDeleteTextures(1, &This
->depth_blt_texture
);
6287 This
->depth_blt_texture
= 0;
6289 if (This
->depth_blt_rb
) {
6290 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &This
->depth_blt_rb
);
6291 This
->depth_blt_rb
= 0;
6292 This
->depth_blt_rb_w
= 0;
6293 This
->depth_blt_rb_h
= 0;
6297 This
->blitter
->free_private(iface
);
6298 This
->frag_pipe
->free_private(iface
);
6299 This
->shader_backend
->shader_free_private(iface
);
6300 destroy_dummy_textures(This
, gl_info
);
6302 context_release(context
);
6304 while (This
->numContexts
)
6306 context_destroy(This
, This
->contexts
[0]);
6308 HeapFree(GetProcessHeap(), 0, swapchain
->context
);
6309 swapchain
->context
= NULL
;
6310 swapchain
->num_contexts
= 0;
6313 HRESULT
create_primary_opengl_context(IWineD3DDevice
*iface
, IWineD3DSwapChain
*swapchain_iface
) {
6314 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6315 IWineD3DSwapChainImpl
*swapchain
= (IWineD3DSwapChainImpl
*) swapchain_iface
;
6316 struct wined3d_context
*context
;
6318 IWineD3DSurfaceImpl
*target
;
6320 /* Recreate the primary swapchain's context */
6321 swapchain
->context
= HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain
->context
));
6322 if (!swapchain
->context
)
6324 ERR("Failed to allocate memory for swapchain context array.\n");
6325 return E_OUTOFMEMORY
;
6328 target
= (IWineD3DSurfaceImpl
*)(swapchain
->backBuffer
? swapchain
->backBuffer
[0] : swapchain
->frontBuffer
);
6329 context
= context_create(This
, target
, swapchain
->win_handle
, FALSE
, &swapchain
->presentParms
);
6332 WARN("Failed to create context.\n");
6333 HeapFree(GetProcessHeap(), 0, swapchain
->context
);
6337 swapchain
->context
[0] = context
;
6338 swapchain
->num_contexts
= 1;
6339 create_dummy_textures(This
);
6340 context_release(context
);
6342 hr
= This
->shader_backend
->shader_alloc_private(iface
);
6345 ERR("Failed to allocate shader private data, hr %#x.\n", hr
);
6349 hr
= This
->frag_pipe
->alloc_private(iface
);
6352 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr
);
6353 This
->shader_backend
->shader_free_private(iface
);
6357 hr
= This
->blitter
->alloc_private(iface
);
6360 ERR("Failed to allocate blitter private data, hr %#x.\n", hr
);
6361 This
->frag_pipe
->free_private(iface
);
6362 This
->shader_backend
->shader_free_private(iface
);
6369 context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
6370 destroy_dummy_textures(This
, context
->gl_info
);
6371 context_release(context
);
6372 context_destroy(This
, context
);
6373 HeapFree(GetProcessHeap(), 0, swapchain
->context
);
6374 swapchain
->num_contexts
= 0;
6378 static HRESULT WINAPI
IWineD3DDeviceImpl_Reset(IWineD3DDevice
* iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
) {
6379 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6380 IWineD3DSwapChainImpl
*swapchain
;
6382 BOOL DisplayModeChanged
= FALSE
;
6383 WINED3DDISPLAYMODE mode
;
6384 TRACE("(%p)\n", This
);
6386 hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**) &swapchain
);
6388 ERR("Failed to get the first implicit swapchain\n");
6392 if(!is_display_mode_supported(This
, pPresentationParameters
)) {
6393 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6394 WARN("Requested mode: %d, %d\n", pPresentationParameters
->BackBufferWidth
,
6395 pPresentationParameters
->BackBufferHeight
);
6396 IWineD3DSwapChain_Release((IWineD3DSwapChain
*)swapchain
);
6397 return WINED3DERR_INVALIDCALL
;
6400 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6401 * on an existing gl context, so there's no real need for recreation.
6403 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6405 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6407 TRACE("New params:\n");
6408 TRACE("BackBufferWidth = %d\n", pPresentationParameters
->BackBufferWidth
);
6409 TRACE("BackBufferHeight = %d\n", pPresentationParameters
->BackBufferHeight
);
6410 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters
->BackBufferFormat
));
6411 TRACE("BackBufferCount = %d\n", pPresentationParameters
->BackBufferCount
);
6412 TRACE("MultiSampleType = %d\n", pPresentationParameters
->MultiSampleType
);
6413 TRACE("MultiSampleQuality = %d\n", pPresentationParameters
->MultiSampleQuality
);
6414 TRACE("SwapEffect = %d\n", pPresentationParameters
->SwapEffect
);
6415 TRACE("hDeviceWindow = %p\n", pPresentationParameters
->hDeviceWindow
);
6416 TRACE("Windowed = %s\n", pPresentationParameters
->Windowed
? "true" : "false");
6417 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters
->EnableAutoDepthStencil
? "true" : "false");
6418 TRACE("Flags = %08x\n", pPresentationParameters
->Flags
);
6419 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters
->FullScreen_RefreshRateInHz
);
6420 TRACE("PresentationInterval = %d\n", pPresentationParameters
->PresentationInterval
);
6422 /* No special treatment of these parameters. Just store them */
6423 swapchain
->presentParms
.SwapEffect
= pPresentationParameters
->SwapEffect
;
6424 swapchain
->presentParms
.Flags
= pPresentationParameters
->Flags
;
6425 swapchain
->presentParms
.PresentationInterval
= pPresentationParameters
->PresentationInterval
;
6426 swapchain
->presentParms
.FullScreen_RefreshRateInHz
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
6428 /* What to do about these? */
6429 if(pPresentationParameters
->BackBufferCount
!= 0 &&
6430 pPresentationParameters
->BackBufferCount
!= swapchain
->presentParms
.BackBufferCount
) {
6431 ERR("Cannot change the back buffer count yet\n");
6433 if(pPresentationParameters
->BackBufferFormat
!= WINED3DFMT_UNKNOWN
&&
6434 pPresentationParameters
->BackBufferFormat
!= swapchain
->presentParms
.BackBufferFormat
) {
6435 ERR("Cannot change the back buffer format yet\n");
6437 if(pPresentationParameters
->hDeviceWindow
!= NULL
&&
6438 pPresentationParameters
->hDeviceWindow
!= swapchain
->presentParms
.hDeviceWindow
) {
6439 ERR("Cannot change the device window yet\n");
6441 if (pPresentationParameters
->EnableAutoDepthStencil
&& !This
->auto_depth_stencil_buffer
) {
6444 TRACE("Creating the depth stencil buffer\n");
6446 hrc
= IWineD3DDeviceParent_CreateDepthStencilSurface(This
->device_parent
,
6448 pPresentationParameters
->BackBufferWidth
,
6449 pPresentationParameters
->BackBufferHeight
,
6450 pPresentationParameters
->AutoDepthStencilFormat
,
6451 pPresentationParameters
->MultiSampleType
,
6452 pPresentationParameters
->MultiSampleQuality
,
6454 &This
->auto_depth_stencil_buffer
);
6457 ERR("Failed to create the depth stencil buffer\n");
6458 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
6459 return WINED3DERR_INVALIDCALL
;
6463 /* Reset the depth stencil */
6464 if (pPresentationParameters
->EnableAutoDepthStencil
)
6465 IWineD3DDevice_SetDepthStencilSurface(iface
, This
->auto_depth_stencil_buffer
);
6467 IWineD3DDevice_SetDepthStencilSurface(iface
, NULL
);
6469 TRACE("Resetting stateblock\n");
6470 IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
);
6471 IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->stateBlock
);
6473 delete_opengl_contexts(iface
, (IWineD3DSwapChain
*) swapchain
);
6475 if(pPresentationParameters
->Windowed
) {
6476 mode
.Width
= swapchain
->orig_width
;
6477 mode
.Height
= swapchain
->orig_height
;
6478 mode
.RefreshRate
= 0;
6479 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
6481 mode
.Width
= pPresentationParameters
->BackBufferWidth
;
6482 mode
.Height
= pPresentationParameters
->BackBufferHeight
;
6483 mode
.RefreshRate
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
6484 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
6487 /* Should Width == 800 && Height == 0 set 800x600? */
6488 if(pPresentationParameters
->BackBufferWidth
!= 0 && pPresentationParameters
->BackBufferHeight
!= 0 &&
6489 (pPresentationParameters
->BackBufferWidth
!= swapchain
->presentParms
.BackBufferWidth
||
6490 pPresentationParameters
->BackBufferHeight
!= swapchain
->presentParms
.BackBufferHeight
))
6494 if(!pPresentationParameters
->Windowed
) {
6495 DisplayModeChanged
= TRUE
;
6497 swapchain
->presentParms
.BackBufferWidth
= pPresentationParameters
->BackBufferWidth
;
6498 swapchain
->presentParms
.BackBufferHeight
= pPresentationParameters
->BackBufferHeight
;
6500 hr
= updateSurfaceDesc((IWineD3DSurfaceImpl
*)swapchain
->frontBuffer
, pPresentationParameters
);
6503 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
6507 for(i
= 0; i
< swapchain
->presentParms
.BackBufferCount
; i
++) {
6508 hr
= updateSurfaceDesc((IWineD3DSurfaceImpl
*)swapchain
->backBuffer
[i
], pPresentationParameters
);
6511 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
6515 if(This
->auto_depth_stencil_buffer
) {
6516 hr
= updateSurfaceDesc((IWineD3DSurfaceImpl
*)This
->auto_depth_stencil_buffer
, pPresentationParameters
);
6519 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
6525 if((pPresentationParameters
->Windowed
&& !swapchain
->presentParms
.Windowed
) ||
6526 (swapchain
->presentParms
.Windowed
&& !pPresentationParameters
->Windowed
) ||
6527 DisplayModeChanged
) {
6529 IWineD3DDevice_SetDisplayMode(iface
, 0, &mode
);
6531 if(swapchain
->win_handle
&& !pPresentationParameters
->Windowed
) {
6532 if(swapchain
->presentParms
.Windowed
) {
6533 /* switch from windowed to fs */
6534 swapchain_setup_fullscreen_window(swapchain
, pPresentationParameters
->BackBufferWidth
,
6535 pPresentationParameters
->BackBufferHeight
);
6537 /* Fullscreen -> fullscreen mode change */
6538 MoveWindow(swapchain
->win_handle
, 0, 0,
6539 pPresentationParameters
->BackBufferWidth
, pPresentationParameters
->BackBufferHeight
,
6542 } else if(swapchain
->win_handle
&& !swapchain
->presentParms
.Windowed
) {
6543 /* Fullscreen -> windowed switch */
6544 swapchain_restore_fullscreen_window(swapchain
);
6546 swapchain
->presentParms
.Windowed
= pPresentationParameters
->Windowed
;
6547 } else if(!pPresentationParameters
->Windowed
) {
6548 DWORD style
= This
->style
, exStyle
= This
->exStyle
;
6549 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6550 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6551 * Reset to clear up their mess. Guild Wars also loses the device during that.
6555 swapchain_setup_fullscreen_window(swapchain
, pPresentationParameters
->BackBufferWidth
,
6556 pPresentationParameters
->BackBufferHeight
);
6557 This
->style
= style
;
6558 This
->exStyle
= exStyle
;
6561 /* Note: No parent needed for initial internal stateblock */
6562 hr
= IWineD3DDevice_CreateStateBlock(iface
, WINED3DSBT_INIT
, (IWineD3DStateBlock
**)&This
->stateBlock
, NULL
);
6563 if (FAILED(hr
)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr
);
6564 else TRACE("Created stateblock %p\n", This
->stateBlock
);
6565 This
->updateStateBlock
= This
->stateBlock
;
6566 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
6568 hr
= IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock
*) This
->stateBlock
);
6570 ERR("Resetting the stateblock failed with error 0x%08x\n", hr
);
6573 if(wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
)
6576 GetClientRect(swapchain
->win_handle
, &client_rect
);
6578 if(!swapchain
->presentParms
.BackBufferCount
)
6580 TRACE("Single buffered rendering\n");
6581 swapchain
->render_to_fbo
= FALSE
;
6583 else if(swapchain
->presentParms
.BackBufferWidth
!= client_rect
.right
||
6584 swapchain
->presentParms
.BackBufferHeight
!= client_rect
.bottom
)
6586 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6587 swapchain
->presentParms
.BackBufferWidth
,
6588 swapchain
->presentParms
.BackBufferHeight
,
6589 client_rect
.right
, client_rect
.bottom
);
6590 swapchain
->render_to_fbo
= TRUE
;
6594 TRACE("Rendering directly to GL_BACK\n");
6595 swapchain
->render_to_fbo
= FALSE
;
6599 hr
= create_primary_opengl_context(iface
, (IWineD3DSwapChain
*) swapchain
);
6600 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
6602 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6608 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice
*iface
, BOOL enable_dialogs
)
6610 TRACE("iface %p, enable_dialogs %#x.\n", iface
, enable_dialogs
);
6612 if (!enable_dialogs
) FIXME("Dialogs cannot be disabled yet.\n");
6618 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice
*iface
, WINED3DDEVICE_CREATION_PARAMETERS
*pParameters
) {
6619 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6620 TRACE("(%p) : pParameters %p\n", This
, pParameters
);
6622 *pParameters
= This
->createParms
;
6626 static void WINAPI
IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice
* iface
, UINT iSwapChain
, DWORD Flags
, CONST WINED3DGAMMARAMP
* pRamp
) {
6627 IWineD3DSwapChain
*swapchain
;
6629 TRACE("Relaying to swapchain\n");
6631 if (IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
) == WINED3D_OK
) {
6632 IWineD3DSwapChain_SetGammaRamp(swapchain
, Flags
, pRamp
);
6633 IWineD3DSwapChain_Release(swapchain
);
6637 static void WINAPI
IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DGAMMARAMP
* pRamp
) {
6638 IWineD3DSwapChain
*swapchain
;
6640 TRACE("Relaying to swapchain\n");
6642 if (IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
) == WINED3D_OK
) {
6643 IWineD3DSwapChain_GetGammaRamp(swapchain
, pRamp
);
6644 IWineD3DSwapChain_Release(swapchain
);
6649 /** ********************************************************
6650 * Notification functions
6651 ** ********************************************************/
6652 /** This function must be called in the release of a resource when ref == 0,
6653 * the contents of resource must still be correct,
6654 * any handles to other resource held by the caller must be closed
6655 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6656 *****************************************************/
6657 void device_resource_add(IWineD3DDeviceImpl
*This
, IWineD3DResource
*resource
)
6659 TRACE("(%p) : Adding resource %p\n", This
, resource
);
6661 list_add_head(&This
->resources
, &((IWineD3DResourceImpl
*) resource
)->resource
.resource_list_entry
);
6664 static void device_resource_remove(IWineD3DDeviceImpl
*This
, IWineD3DResource
*resource
)
6666 TRACE("(%p) : Removing resource %p\n", This
, resource
);
6668 list_remove(&((IWineD3DResourceImpl
*) resource
)->resource
.resource_list_entry
);
6671 void device_resource_released(IWineD3DDeviceImpl
*This
, IWineD3DResource
*resource
)
6673 WINED3DRESOURCETYPE type
= IWineD3DResource_GetType(resource
);
6676 TRACE("(%p) : resource %p\n", This
, resource
);
6678 context_resource_released((IWineD3DDevice
*)This
, resource
, type
);
6681 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6682 case WINED3DRTYPE_SURFACE
: {
6685 if (This
->d3d_initialized
)
6687 for (i
= 0; i
< This
->adapter
->gl_info
.limits
.buffers
; ++i
)
6689 if (This
->render_targets
[i
] == (IWineD3DSurface
*)resource
) {
6690 This
->render_targets
[i
] = NULL
;
6693 if (This
->stencilBufferTarget
== (IWineD3DSurface
*)resource
) {
6694 This
->stencilBufferTarget
= NULL
;
6700 case WINED3DRTYPE_TEXTURE
:
6701 case WINED3DRTYPE_CUBETEXTURE
:
6702 case WINED3DRTYPE_VOLUMETEXTURE
:
6703 for (counter
= 0; counter
< MAX_COMBINED_SAMPLERS
; counter
++) {
6704 if (This
->stateBlock
!= NULL
&& This
->stateBlock
->textures
[counter
] == (IWineD3DBaseTexture
*)resource
) {
6705 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter
, resource
);
6706 This
->stateBlock
->textures
[counter
] = NULL
;
6708 if (This
->updateStateBlock
!= This
->stateBlock
){
6709 if (This
->updateStateBlock
->textures
[counter
] == (IWineD3DBaseTexture
*)resource
) {
6710 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter
, resource
);
6711 This
->updateStateBlock
->textures
[counter
] = NULL
;
6716 case WINED3DRTYPE_VOLUME
:
6717 /* TODO: nothing really? */
6719 case WINED3DRTYPE_BUFFER
:
6722 TRACE("Cleaning up stream pointers\n");
6724 for(streamNumber
= 0; streamNumber
< MAX_STREAMS
; streamNumber
++){
6725 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6726 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6728 if (This
->updateStateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
6729 if ((IWineD3DResource
*)This
->updateStateBlock
->streamSource
[streamNumber
] == resource
) {
6730 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber
);
6731 This
->updateStateBlock
->streamSource
[streamNumber
] = 0;
6732 /* Set changed flag? */
6735 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) */
6736 if ((IWineD3DResource
*)This
->stateBlock
->streamSource
[streamNumber
] == resource
) {
6737 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber
);
6738 This
->stateBlock
->streamSource
[streamNumber
] = 0;
6743 if (This
->updateStateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
6744 if (This
->updateStateBlock
->pIndexData
== (IWineD3DBuffer
*)resource
) {
6745 This
->updateStateBlock
->pIndexData
= NULL
;
6748 if (This
->stateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
6749 if (This
->stateBlock
->pIndexData
== (IWineD3DBuffer
*)resource
) {
6750 This
->stateBlock
->pIndexData
= NULL
;
6757 FIXME("(%p) unknown resource type %p %u\n", This
, resource
, IWineD3DResource_GetType(resource
));
6762 /* Remove the resource from the resourceStore */
6763 device_resource_remove(This
, resource
);
6765 TRACE("Resource released\n");
6769 static HRESULT WINAPI
IWineD3DDeviceImpl_EnumResources(IWineD3DDevice
*iface
, D3DCB_ENUMRESOURCES pCallback
, void *pData
) {
6770 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6771 IWineD3DResourceImpl
*resource
, *cursor
;
6773 TRACE("(%p)->(%p,%p)\n", This
, pCallback
, pData
);
6775 LIST_FOR_EACH_ENTRY_SAFE(resource
, cursor
, &This
->resources
, IWineD3DResourceImpl
, resource
.resource_list_entry
) {
6776 TRACE("enumerating resource %p\n", resource
);
6777 IWineD3DResource_AddRef((IWineD3DResource
*) resource
);
6778 ret
= pCallback((IWineD3DResource
*) resource
, pData
);
6779 if(ret
== S_FALSE
) {
6780 TRACE("Canceling enumeration\n");
6787 /**********************************************************
6788 * IWineD3DDevice VTbl follows
6789 **********************************************************/
6791 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl
=
6793 /*** IUnknown methods ***/
6794 IWineD3DDeviceImpl_QueryInterface
,
6795 IWineD3DDeviceImpl_AddRef
,
6796 IWineD3DDeviceImpl_Release
,
6797 /*** IWineD3DDevice methods ***/
6798 IWineD3DDeviceImpl_GetParent
,
6799 /*** Creation methods**/
6800 IWineD3DDeviceImpl_CreateBuffer
,
6801 IWineD3DDeviceImpl_CreateVertexBuffer
,
6802 IWineD3DDeviceImpl_CreateIndexBuffer
,
6803 IWineD3DDeviceImpl_CreateStateBlock
,
6804 IWineD3DDeviceImpl_CreateSurface
,
6805 IWineD3DDeviceImpl_CreateRendertargetView
,
6806 IWineD3DDeviceImpl_CreateTexture
,
6807 IWineD3DDeviceImpl_CreateVolumeTexture
,
6808 IWineD3DDeviceImpl_CreateVolume
,
6809 IWineD3DDeviceImpl_CreateCubeTexture
,
6810 IWineD3DDeviceImpl_CreateQuery
,
6811 IWineD3DDeviceImpl_CreateSwapChain
,
6812 IWineD3DDeviceImpl_CreateVertexDeclaration
,
6813 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF
,
6814 IWineD3DDeviceImpl_CreateVertexShader
,
6815 IWineD3DDeviceImpl_CreateGeometryShader
,
6816 IWineD3DDeviceImpl_CreatePixelShader
,
6817 IWineD3DDeviceImpl_CreatePalette
,
6818 /*** Odd functions **/
6819 IWineD3DDeviceImpl_Init3D
,
6820 IWineD3DDeviceImpl_InitGDI
,
6821 IWineD3DDeviceImpl_Uninit3D
,
6822 IWineD3DDeviceImpl_UninitGDI
,
6823 IWineD3DDeviceImpl_SetMultithreaded
,
6824 IWineD3DDeviceImpl_EvictManagedResources
,
6825 IWineD3DDeviceImpl_GetAvailableTextureMem
,
6826 IWineD3DDeviceImpl_GetBackBuffer
,
6827 IWineD3DDeviceImpl_GetCreationParameters
,
6828 IWineD3DDeviceImpl_GetDeviceCaps
,
6829 IWineD3DDeviceImpl_GetDirect3D
,
6830 IWineD3DDeviceImpl_GetDisplayMode
,
6831 IWineD3DDeviceImpl_SetDisplayMode
,
6832 IWineD3DDeviceImpl_GetNumberOfSwapChains
,
6833 IWineD3DDeviceImpl_GetRasterStatus
,
6834 IWineD3DDeviceImpl_GetSwapChain
,
6835 IWineD3DDeviceImpl_Reset
,
6836 IWineD3DDeviceImpl_SetDialogBoxMode
,
6837 IWineD3DDeviceImpl_SetCursorProperties
,
6838 IWineD3DDeviceImpl_SetCursorPosition
,
6839 IWineD3DDeviceImpl_ShowCursor
,
6840 /*** Getters and setters **/
6841 IWineD3DDeviceImpl_SetClipPlane
,
6842 IWineD3DDeviceImpl_GetClipPlane
,
6843 IWineD3DDeviceImpl_SetClipStatus
,
6844 IWineD3DDeviceImpl_GetClipStatus
,
6845 IWineD3DDeviceImpl_SetCurrentTexturePalette
,
6846 IWineD3DDeviceImpl_GetCurrentTexturePalette
,
6847 IWineD3DDeviceImpl_SetDepthStencilSurface
,
6848 IWineD3DDeviceImpl_GetDepthStencilSurface
,
6849 IWineD3DDeviceImpl_SetGammaRamp
,
6850 IWineD3DDeviceImpl_GetGammaRamp
,
6851 IWineD3DDeviceImpl_SetIndexBuffer
,
6852 IWineD3DDeviceImpl_GetIndexBuffer
,
6853 IWineD3DDeviceImpl_SetBaseVertexIndex
,
6854 IWineD3DDeviceImpl_GetBaseVertexIndex
,
6855 IWineD3DDeviceImpl_SetLight
,
6856 IWineD3DDeviceImpl_GetLight
,
6857 IWineD3DDeviceImpl_SetLightEnable
,
6858 IWineD3DDeviceImpl_GetLightEnable
,
6859 IWineD3DDeviceImpl_SetMaterial
,
6860 IWineD3DDeviceImpl_GetMaterial
,
6861 IWineD3DDeviceImpl_SetNPatchMode
,
6862 IWineD3DDeviceImpl_GetNPatchMode
,
6863 IWineD3DDeviceImpl_SetPaletteEntries
,
6864 IWineD3DDeviceImpl_GetPaletteEntries
,
6865 IWineD3DDeviceImpl_SetPixelShader
,
6866 IWineD3DDeviceImpl_GetPixelShader
,
6867 IWineD3DDeviceImpl_SetPixelShaderConstantB
,
6868 IWineD3DDeviceImpl_GetPixelShaderConstantB
,
6869 IWineD3DDeviceImpl_SetPixelShaderConstantI
,
6870 IWineD3DDeviceImpl_GetPixelShaderConstantI
,
6871 IWineD3DDeviceImpl_SetPixelShaderConstantF
,
6872 IWineD3DDeviceImpl_GetPixelShaderConstantF
,
6873 IWineD3DDeviceImpl_SetRenderState
,
6874 IWineD3DDeviceImpl_GetRenderState
,
6875 IWineD3DDeviceImpl_SetRenderTarget
,
6876 IWineD3DDeviceImpl_GetRenderTarget
,
6877 IWineD3DDeviceImpl_SetFrontBackBuffers
,
6878 IWineD3DDeviceImpl_SetSamplerState
,
6879 IWineD3DDeviceImpl_GetSamplerState
,
6880 IWineD3DDeviceImpl_SetScissorRect
,
6881 IWineD3DDeviceImpl_GetScissorRect
,
6882 IWineD3DDeviceImpl_SetSoftwareVertexProcessing
,
6883 IWineD3DDeviceImpl_GetSoftwareVertexProcessing
,
6884 IWineD3DDeviceImpl_SetStreamSource
,
6885 IWineD3DDeviceImpl_GetStreamSource
,
6886 IWineD3DDeviceImpl_SetStreamSourceFreq
,
6887 IWineD3DDeviceImpl_GetStreamSourceFreq
,
6888 IWineD3DDeviceImpl_SetTexture
,
6889 IWineD3DDeviceImpl_GetTexture
,
6890 IWineD3DDeviceImpl_SetTextureStageState
,
6891 IWineD3DDeviceImpl_GetTextureStageState
,
6892 IWineD3DDeviceImpl_SetTransform
,
6893 IWineD3DDeviceImpl_GetTransform
,
6894 IWineD3DDeviceImpl_SetVertexDeclaration
,
6895 IWineD3DDeviceImpl_GetVertexDeclaration
,
6896 IWineD3DDeviceImpl_SetVertexShader
,
6897 IWineD3DDeviceImpl_GetVertexShader
,
6898 IWineD3DDeviceImpl_SetVertexShaderConstantB
,
6899 IWineD3DDeviceImpl_GetVertexShaderConstantB
,
6900 IWineD3DDeviceImpl_SetVertexShaderConstantI
,
6901 IWineD3DDeviceImpl_GetVertexShaderConstantI
,
6902 IWineD3DDeviceImpl_SetVertexShaderConstantF
,
6903 IWineD3DDeviceImpl_GetVertexShaderConstantF
,
6904 IWineD3DDeviceImpl_SetViewport
,
6905 IWineD3DDeviceImpl_GetViewport
,
6906 IWineD3DDeviceImpl_MultiplyTransform
,
6907 IWineD3DDeviceImpl_ValidateDevice
,
6908 IWineD3DDeviceImpl_ProcessVertices
,
6909 /*** State block ***/
6910 IWineD3DDeviceImpl_BeginStateBlock
,
6911 IWineD3DDeviceImpl_EndStateBlock
,
6912 /*** Scene management ***/
6913 IWineD3DDeviceImpl_BeginScene
,
6914 IWineD3DDeviceImpl_EndScene
,
6915 IWineD3DDeviceImpl_Present
,
6916 IWineD3DDeviceImpl_Clear
,
6917 IWineD3DDeviceImpl_ClearRendertargetView
,
6919 IWineD3DDeviceImpl_SetPrimitiveType
,
6920 IWineD3DDeviceImpl_GetPrimitiveType
,
6921 IWineD3DDeviceImpl_DrawPrimitive
,
6922 IWineD3DDeviceImpl_DrawIndexedPrimitive
,
6923 IWineD3DDeviceImpl_DrawPrimitiveUP
,
6924 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP
,
6925 IWineD3DDeviceImpl_DrawPrimitiveStrided
,
6926 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided
,
6927 IWineD3DDeviceImpl_DrawRectPatch
,
6928 IWineD3DDeviceImpl_DrawTriPatch
,
6929 IWineD3DDeviceImpl_DeletePatch
,
6930 IWineD3DDeviceImpl_ColorFill
,
6931 IWineD3DDeviceImpl_UpdateTexture
,
6932 IWineD3DDeviceImpl_UpdateSurface
,
6933 IWineD3DDeviceImpl_GetFrontBufferData
,
6934 /*** object tracking ***/
6935 IWineD3DDeviceImpl_EnumResources
6938 HRESULT
device_init(IWineD3DDeviceImpl
*device
, IWineD3DImpl
*wined3d
,
6939 UINT adapter_idx
, WINED3DDEVTYPE device_type
, HWND focus_window
, DWORD flags
,
6940 IUnknown
*parent
, IWineD3DDeviceParent
*device_parent
)
6942 struct wined3d_adapter
*adapter
= &wined3d
->adapters
[adapter_idx
];
6943 const struct fragment_pipeline
*fragment_pipeline
;
6944 struct shader_caps shader_caps
;
6945 struct fragment_caps ffp_caps
;
6946 WINED3DDISPLAYMODE mode
;
6950 device
->lpVtbl
= &IWineD3DDevice_Vtbl
;
6952 device
->wined3d
= (IWineD3D
*)wined3d
;
6953 IWineD3D_AddRef(device
->wined3d
);
6954 device
->adapter
= wined3d
->adapter_count
? adapter
: NULL
;
6955 device
->parent
= parent
;
6956 device
->device_parent
= device_parent
;
6957 list_init(&device
->resources
);
6958 list_init(&device
->shaders
);
6960 device
->surface_alignment
= wined3d
->dxVersion
== 7 ? DDRAW_PITCH_ALIGNMENT
: D3D8_PITCH_ALIGNMENT
;
6961 device
->posFixup
[0] = 1.0f
; /* This is needed to get the x coord unmodified through a MAD. */
6963 /* Get the initial screen setup for ddraw. */
6964 hr
= IWineD3D_GetAdapterDisplayMode((IWineD3D
*)wined3d
, adapter_idx
, &mode
);
6967 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr
);
6968 IWineD3D_Release(device
->wined3d
);
6971 device
->ddraw_width
= mode
.Width
;
6972 device
->ddraw_height
= mode
.Height
;
6973 device
->ddraw_format
= mode
.Format
;
6975 /* Save the creation parameters. */
6976 device
->createParms
.AdapterOrdinal
= adapter_idx
;
6977 device
->createParms
.DeviceType
= device_type
;
6978 device
->createParms
.hFocusWindow
= focus_window
;
6979 device
->createParms
.BehaviorFlags
= flags
;
6981 device
->devType
= device_type
;
6982 for (i
= 0; i
< PATCHMAP_SIZE
; ++i
) list_init(&device
->patches
[i
]);
6984 select_shader_mode(&adapter
->gl_info
, &device
->ps_selected_mode
, &device
->vs_selected_mode
);
6985 device
->shader_backend
= select_shader_backend(adapter
, device_type
);
6987 memset(&shader_caps
, 0, sizeof(shader_caps
));
6988 device
->shader_backend
->shader_get_caps(device_type
, &adapter
->gl_info
, &shader_caps
);
6989 device
->d3d_vshader_constantF
= shader_caps
.MaxVertexShaderConst
;
6990 device
->d3d_pshader_constantF
= shader_caps
.MaxPixelShaderConst
;
6991 device
->vs_clipping
= shader_caps
.VSClipping
;
6993 memset(&ffp_caps
, 0, sizeof(ffp_caps
));
6994 fragment_pipeline
= select_fragment_implementation(adapter
, device_type
);
6995 device
->frag_pipe
= fragment_pipeline
;
6996 fragment_pipeline
->get_caps(device_type
, &adapter
->gl_info
, &ffp_caps
);
6997 device
->max_ffp_textures
= ffp_caps
.MaxSimultaneousTextures
;
6998 device
->max_ffp_texture_stages
= ffp_caps
.MaxTextureBlendStages
;
7000 hr
= compile_state_table(device
->StateTable
, device
->multistate_funcs
, &adapter
->gl_info
,
7001 ffp_vertexstate_template
, fragment_pipeline
, misc_state_template
);
7004 ERR("Failed to compile state table, hr %#x.\n", hr
);
7005 IWineD3D_Release(device
->wined3d
);
7009 device
->blitter
= select_blit_implementation(adapter
, device_type
);
7015 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl
*This
, DWORD state
) {
7016 DWORD rep
= This
->StateTable
[state
].representative
;
7017 struct wined3d_context
*context
;
7022 for(i
= 0; i
< This
->numContexts
; i
++) {
7023 context
= This
->contexts
[i
];
7024 if(isStateDirty(context
, rep
)) continue;
7026 context
->dirtyArray
[context
->numDirtyEntries
++] = rep
;
7027 idx
= rep
/ (sizeof(*context
->isStateDirty
) * CHAR_BIT
);
7028 shift
= rep
& ((sizeof(*context
->isStateDirty
) * CHAR_BIT
) - 1);
7029 context
->isStateDirty
[idx
] |= (1 << shift
);
7033 void get_drawable_size_pbuffer(struct wined3d_context
*context
, UINT
*width
, UINT
*height
)
7035 IWineD3DDeviceImpl
*device
= ((IWineD3DSurfaceImpl
*)context
->current_rt
)->resource
.device
;
7036 /* The drawable size of a pbuffer render target is the current pbuffer size. */
7037 *width
= device
->pbufferWidth
;
7038 *height
= device
->pbufferHeight
;
7041 void get_drawable_size_fbo(struct wined3d_context
*context
, UINT
*width
, UINT
*height
)
7043 IWineD3DSurfaceImpl
*surface
= (IWineD3DSurfaceImpl
*)context
->current_rt
;
7044 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7045 *width
= surface
->pow2Width
;
7046 *height
= surface
->pow2Height
;
7049 void get_drawable_size_backbuffer(struct wined3d_context
*context
, UINT
*width
, UINT
*height
)
7051 IWineD3DSurfaceImpl
*surface
= (IWineD3DSurfaceImpl
*)context
->surface
;
7052 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7053 * current context's drawable, which is the size of the back buffer of the swapchain
7054 * the active context belongs to. The back buffer of the swapchain is stored as the
7055 * surface the context belongs to. */
7056 *width
= surface
->currentDesc
.Width
;
7057 *height
= surface
->currentDesc
.Height
;
7060 LRESULT
device_process_message(IWineD3DDeviceImpl
*device
, HWND window
,
7061 UINT message
, WPARAM wparam
, LPARAM lparam
, WNDPROC proc
)
7063 if (device
->filter_messages
)
7065 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7066 window
, message
, wparam
, lparam
);
7067 return DefWindowProcW(window
, message
, wparam
, lparam
);
7070 if (message
== WM_DESTROY
)
7072 TRACE("unregister window %p.\n", window
);
7073 wined3d_unregister_window(window
);
7075 if (device
->focus_window
== window
) device
->focus_window
= NULL
;
7076 else ERR("Window %p is not the focus window for device %p.\n", window
, device
);
7079 return CallWindowProcW(proc
, window
, message
, wparam
, lparam
);