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
, UINT Size
,
483 DWORD Usage
, DWORD FVF
, WINED3DPOOL Pool
, IWineD3DBuffer
**ppVertexBuffer
,
484 IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
)
486 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
487 struct wined3d_buffer
*object
;
491 if (Pool
== WINED3DPOOL_SCRATCH
)
493 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
494 * anyway, SCRATCH vertex buffers aren't usable anywhere
496 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
497 *ppVertexBuffer
= NULL
;
498 return WINED3DERR_INVALIDCALL
;
501 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
504 ERR("Out of memory\n");
505 *ppVertexBuffer
= NULL
;
506 return WINED3DERR_OUTOFVIDEOMEMORY
;
509 hr
= buffer_init(object
, This
, Size
, Usage
, WINED3DFMT_VERTEXDATA
,
510 Pool
, GL_ARRAY_BUFFER_ARB
, NULL
, parent
, parent_ops
);
513 WARN("Failed to initialize buffer, hr %#x.\n", hr
);
514 HeapFree(GetProcessHeap(), 0, object
);
518 TRACE("Created buffer %p.\n", object
);
519 TRACE("FVF %#x, Pool %#x.\n", FVF
, Pool
);
520 *ppVertexBuffer
= (IWineD3DBuffer
*)object
;
522 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
523 * drawStridedFast (half-life 2).
525 * Basically converting the vertices in the buffer is quite expensive, and observations
526 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
527 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
529 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
530 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
531 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
532 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
534 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
535 * more. In this call we can convert dx7 buffers too.
537 conv
= ((FVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) || (FVF
& (WINED3DFVF_DIFFUSE
| WINED3DFVF_SPECULAR
));
538 if (!This
->adapter
->gl_info
.supported
[ARB_VERTEX_BUFFER_OBJECT
])
540 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
541 } else if(Pool
== WINED3DPOOL_SYSTEMMEM
) {
542 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
543 } else if(Usage
& WINED3DUSAGE_DYNAMIC
) {
544 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
545 } else if(!(Usage
& WINED3DUSAGE_OPTIMIZE
) && conv
) {
546 TRACE("Not creating a vbo because the fvf needs conversion, but VB optimization is disabled\n");
548 object
->flags
|= WINED3D_BUFFER_CREATEBO
;
553 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice
*iface
,
554 UINT Length
, DWORD Usage
, WINED3DPOOL Pool
, IWineD3DBuffer
**ppIndexBuffer
,
555 IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
)
557 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
558 struct wined3d_buffer
*object
;
561 TRACE("(%p) Creating index buffer\n", This
);
563 /* Allocate the storage for the device */
564 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
567 ERR("Out of memory\n");
568 *ppIndexBuffer
= NULL
;
569 return WINED3DERR_OUTOFVIDEOMEMORY
;
572 hr
= buffer_init(object
, This
, Length
, Usage
| WINED3DUSAGE_STATICDECL
,
573 WINED3DFMT_UNKNOWN
, Pool
, GL_ELEMENT_ARRAY_BUFFER_ARB
, NULL
, parent
, parent_ops
);
576 WARN("Failed to initialize buffer, hr %#x\n", hr
);
577 HeapFree(GetProcessHeap(), 0, object
);
581 TRACE("Created buffer %p.\n", object
);
583 if (Pool
!= WINED3DPOOL_SYSTEMMEM
&& !(Usage
& WINED3DUSAGE_DYNAMIC
)
584 && This
->adapter
->gl_info
.supported
[ARB_VERTEX_BUFFER_OBJECT
])
586 object
->flags
|= WINED3D_BUFFER_CREATEBO
;
589 *ppIndexBuffer
= (IWineD3DBuffer
*) object
;
594 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice
*iface
,
595 WINED3DSTATEBLOCKTYPE type
, IWineD3DStateBlock
**stateblock
, IUnknown
*parent
)
597 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
598 IWineD3DStateBlockImpl
*object
;
601 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
604 ERR("Failed to allocate stateblock memory.\n");
605 return E_OUTOFMEMORY
;
608 hr
= stateblock_init(object
, This
, type
);
611 WARN("Failed to initialize stateblock, hr %#x.\n", hr
);
612 HeapFree(GetProcessHeap(), 0, object
);
616 TRACE("Created stateblock %p.\n", object
);
617 *stateblock
= (IWineD3DStateBlock
*)object
;
622 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice
*iface
, UINT Width
, UINT Height
,
623 WINED3DFORMAT Format
, BOOL Lockable
, BOOL Discard
, UINT Level
, IWineD3DSurface
**ppSurface
,
624 DWORD Usage
, WINED3DPOOL Pool
, WINED3DMULTISAMPLE_TYPE MultiSample
, DWORD MultisampleQuality
,
625 WINED3DSURFTYPE Impl
, IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
)
627 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
628 IWineD3DSurfaceImpl
*object
;
631 TRACE("(%p) Create surface\n",This
);
633 if (Impl
== SURFACE_OPENGL
&& !This
->adapter
)
635 ERR("OpenGL surfaces are not available without OpenGL.\n");
636 return WINED3DERR_NOTAVAILABLE
;
639 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
642 ERR("Failed to allocate surface memory.\n");
644 return WINED3DERR_OUTOFVIDEOMEMORY
;
647 hr
= surface_init(object
, Impl
, This
->surface_alignment
, Width
, Height
, Level
, Lockable
,
648 Discard
, MultiSample
, MultisampleQuality
, This
, Usage
, Format
, Pool
, parent
, parent_ops
);
651 WARN("Failed to initialize surface, returning %#x.\n", hr
);
652 HeapFree(GetProcessHeap(), 0, object
);
657 TRACE("(%p) : Created surface %p\n", This
, object
);
659 *ppSurface
= (IWineD3DSurface
*)object
;
664 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice
*iface
,
665 IWineD3DResource
*resource
, IUnknown
*parent
, IWineD3DRendertargetView
**rendertarget_view
)
667 struct wined3d_rendertarget_view
*object
;
669 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
672 ERR("Failed to allocate memory\n");
673 return E_OUTOFMEMORY
;
676 object
->vtbl
= &wined3d_rendertarget_view_vtbl
;
677 object
->refcount
= 1;
678 IWineD3DResource_AddRef(resource
);
679 object
->resource
= resource
;
680 object
->parent
= parent
;
682 *rendertarget_view
= (IWineD3DRendertargetView
*)object
;
687 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice
*iface
,
688 UINT Width
, UINT Height
, UINT Levels
, DWORD Usage
, WINED3DFORMAT Format
, WINED3DPOOL Pool
,
689 IWineD3DTexture
**ppTexture
, IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
)
691 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
692 IWineD3DTextureImpl
*object
;
695 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This
, Width
, Height
, Levels
, Usage
);
696 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
697 Format
, debug_d3dformat(Format
), Pool
, ppTexture
, parent
);
699 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
702 ERR("Out of memory\n");
704 return WINED3DERR_OUTOFVIDEOMEMORY
;
707 hr
= texture_init(object
, Width
, Height
, Levels
, This
, Usage
, Format
, Pool
, parent
, parent_ops
);
710 WARN("Failed to initialize texture, returning %#x\n", hr
);
711 HeapFree(GetProcessHeap(), 0, object
);
716 *ppTexture
= (IWineD3DTexture
*)object
;
718 TRACE("(%p) : Created texture %p\n", This
, object
);
723 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice
*iface
,
724 UINT Width
, UINT Height
, UINT Depth
, UINT Levels
, DWORD Usage
, WINED3DFORMAT Format
, WINED3DPOOL Pool
,
725 IWineD3DVolumeTexture
**ppVolumeTexture
, IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
)
727 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
728 IWineD3DVolumeTextureImpl
*object
;
731 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
732 Depth
, Levels
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
734 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
737 ERR("Out of memory\n");
738 *ppVolumeTexture
= NULL
;
739 return WINED3DERR_OUTOFVIDEOMEMORY
;
742 hr
= volumetexture_init(object
, Width
, Height
, Depth
, Levels
, This
, Usage
, Format
, Pool
, parent
, parent_ops
);
745 WARN("Failed to initialize volumetexture, returning %#x\n", hr
);
746 HeapFree(GetProcessHeap(), 0, object
);
747 *ppVolumeTexture
= NULL
;
751 TRACE("(%p) : Created volume texture %p.\n", This
, object
);
752 *ppVolumeTexture
= (IWineD3DVolumeTexture
*)object
;
757 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice
*iface
, UINT Width
, UINT Height
,
758 UINT Depth
, DWORD Usage
, WINED3DFORMAT Format
, WINED3DPOOL Pool
, IWineD3DVolume
**ppVolume
,
759 IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
)
761 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
762 IWineD3DVolumeImpl
*object
;
765 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
766 Depth
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
768 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
771 ERR("Out of memory\n");
773 return WINED3DERR_OUTOFVIDEOMEMORY
;
776 hr
= volume_init(object
, This
, Width
, Height
, Depth
, Usage
, Format
, Pool
, parent
, parent_ops
);
779 WARN("Failed to initialize volume, returning %#x.\n", hr
);
780 HeapFree(GetProcessHeap(), 0, object
);
784 TRACE("(%p) : Created volume %p.\n", This
, object
);
785 *ppVolume
= (IWineD3DVolume
*)object
;
790 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice
*iface
, UINT EdgeLength
, UINT Levels
,
791 DWORD Usage
, WINED3DFORMAT Format
, WINED3DPOOL Pool
, IWineD3DCubeTexture
**ppCubeTexture
,
792 IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
)
794 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
795 IWineD3DCubeTextureImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
798 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
801 ERR("Out of memory\n");
802 *ppCubeTexture
= NULL
;
803 return WINED3DERR_OUTOFVIDEOMEMORY
;
806 hr
= cubetexture_init(object
, EdgeLength
, Levels
, This
, Usage
, Format
, Pool
, parent
, parent_ops
);
809 WARN("Failed to initialize cubetexture, returning %#x\n", hr
);
810 HeapFree(GetProcessHeap(), 0, object
);
811 *ppCubeTexture
= NULL
;
815 TRACE("(%p) : Created Cube Texture %p\n", This
, object
);
816 *ppCubeTexture
= (IWineD3DCubeTexture
*)object
;
821 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice
*iface
, WINED3DQUERYTYPE Type
, IWineD3DQuery
**ppQuery
, IUnknown
* parent
) {
822 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
823 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
824 IWineD3DQueryImpl
*object
; /*NOTE: impl ref allowed since this is a create function */
825 HRESULT hr
= WINED3DERR_NOTAVAILABLE
;
826 const IWineD3DQueryVtbl
*vtable
;
828 /* Just a check to see if we support this type of query */
830 case WINED3DQUERYTYPE_OCCLUSION
:
831 TRACE("(%p) occlusion query\n", This
);
832 if (gl_info
->supported
[ARB_OCCLUSION_QUERY
])
835 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
837 vtable
= &IWineD3DOcclusionQuery_Vtbl
;
840 case WINED3DQUERYTYPE_EVENT
:
841 if (!gl_info
->supported
[NV_FENCE
] && !gl_info
->supported
[APPLE_FENCE
])
843 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
844 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
846 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This
);
848 vtable
= &IWineD3DEventQuery_Vtbl
;
852 case WINED3DQUERYTYPE_VCACHE
:
853 case WINED3DQUERYTYPE_RESOURCEMANAGER
:
854 case WINED3DQUERYTYPE_VERTEXSTATS
:
855 case WINED3DQUERYTYPE_TIMESTAMP
:
856 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT
:
857 case WINED3DQUERYTYPE_TIMESTAMPFREQ
:
858 case WINED3DQUERYTYPE_PIPELINETIMINGS
:
859 case WINED3DQUERYTYPE_INTERFACETIMINGS
:
860 case WINED3DQUERYTYPE_VERTEXTIMINGS
:
861 case WINED3DQUERYTYPE_PIXELTIMINGS
:
862 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS
:
863 case WINED3DQUERYTYPE_CACHEUTILIZATION
:
865 /* Use the base Query vtable until we have a special one for each query */
866 vtable
= &IWineD3DQuery_Vtbl
;
867 FIXME("(%p) Unhandled query type %d\n", This
, Type
);
869 if(NULL
== ppQuery
|| hr
!= WINED3D_OK
) {
873 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
876 ERR("Out of memory\n");
878 return WINED3DERR_OUTOFVIDEOMEMORY
;
881 object
->lpVtbl
= vtable
;
883 object
->state
= QUERY_CREATED
;
884 object
->wineD3DDevice
= This
;
885 object
->parent
= parent
;
888 *ppQuery
= (IWineD3DQuery
*)object
;
890 /* allocated the 'extended' data based on the type of query requested */
892 case WINED3DQUERYTYPE_OCCLUSION
:
893 object
->extendedData
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_occlusion_query
));
894 ((struct wined3d_occlusion_query
*)object
->extendedData
)->context
= NULL
;
897 case WINED3DQUERYTYPE_EVENT
:
898 object
->extendedData
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_event_query
));
899 ((struct wined3d_event_query
*)object
->extendedData
)->context
= NULL
;
902 case WINED3DQUERYTYPE_VCACHE
:
903 case WINED3DQUERYTYPE_RESOURCEMANAGER
:
904 case WINED3DQUERYTYPE_VERTEXSTATS
:
905 case WINED3DQUERYTYPE_TIMESTAMP
:
906 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT
:
907 case WINED3DQUERYTYPE_TIMESTAMPFREQ
:
908 case WINED3DQUERYTYPE_PIPELINETIMINGS
:
909 case WINED3DQUERYTYPE_INTERFACETIMINGS
:
910 case WINED3DQUERYTYPE_VERTEXTIMINGS
:
911 case WINED3DQUERYTYPE_PIXELTIMINGS
:
912 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS
:
913 case WINED3DQUERYTYPE_CACHEUTILIZATION
:
915 object
->extendedData
= 0;
916 FIXME("(%p) Unhandled query type %d\n",This
, Type
);
918 TRACE("(%p) : Created Query %p\n", This
, object
);
922 /*****************************************************************************
923 * IWineD3DDeviceImpl_SetupFullscreenWindow
925 * Helper function that modifies a HWND's Style and ExStyle for proper
929 * iface: Pointer to the IWineD3DDevice interface
930 * window: Window to setup
932 *****************************************************************************/
933 static LONG
fullscreen_style(LONG orig_style
) {
934 LONG style
= orig_style
;
935 style
&= ~WS_CAPTION
;
936 style
&= ~WS_THICKFRAME
;
938 /* Make sure the window is managed, otherwise we won't get keyboard input */
939 style
|= WS_POPUP
| WS_SYSMENU
;
944 static LONG
fullscreen_exStyle(LONG orig_exStyle
) {
945 LONG exStyle
= orig_exStyle
;
947 /* Filter out window decorations */
948 exStyle
&= ~WS_EX_WINDOWEDGE
;
949 exStyle
&= ~WS_EX_CLIENTEDGE
;
954 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice
*iface
, HWND window
, UINT w
, UINT h
) {
955 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
958 /* Don't do anything if an original style is stored.
959 * That shouldn't happen
961 TRACE("(%p): Setting up window %p for exclusive mode\n", This
, window
);
962 if (This
->style
|| This
->exStyle
) {
963 ERR("(%p): Want to change the window parameters of HWND %p, but "
964 "another style is stored for restoration afterwards\n", This
, window
);
967 /* Get the parameters and save them */
968 style
= GetWindowLongW(window
, GWL_STYLE
);
969 exStyle
= GetWindowLongW(window
, GWL_EXSTYLE
);
971 This
->exStyle
= exStyle
;
973 style
= fullscreen_style(style
);
974 exStyle
= fullscreen_exStyle(exStyle
);
976 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
977 This
->style
, This
->exStyle
, style
, exStyle
);
979 SetWindowLongW(window
, GWL_STYLE
, style
);
980 SetWindowLongW(window
, GWL_EXSTYLE
, exStyle
);
982 /* Inform the window about the update. */
983 SetWindowPos(window
, HWND_TOP
, 0, 0,
984 w
, h
, SWP_FRAMECHANGED
| SWP_SHOWWINDOW
);
987 /*****************************************************************************
988 * IWineD3DDeviceImpl_RestoreWindow
990 * Helper function that restores a windows' properties when taking it out
994 * iface: Pointer to the IWineD3DDevice interface
995 * window: Window to setup
997 *****************************************************************************/
998 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice
*iface
, HWND window
) {
999 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1000 LONG style
, exStyle
;
1002 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1003 * switch, do nothing
1005 if (!This
->style
&& !This
->exStyle
) return;
1007 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1008 This
, window
, This
->style
, This
->exStyle
);
1010 style
= GetWindowLongW(window
, GWL_STYLE
);
1011 exStyle
= GetWindowLongW(window
, GWL_EXSTYLE
);
1013 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1014 * Some applications change it before calling Reset() when switching between windowed and
1015 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1017 if(style
== fullscreen_style(This
->style
) &&
1018 exStyle
== fullscreen_style(This
->exStyle
)) {
1019 SetWindowLongW(window
, GWL_STYLE
, This
->style
);
1020 SetWindowLongW(window
, GWL_EXSTYLE
, This
->exStyle
);
1023 /* Delete the old values */
1027 /* Inform the window about the update */
1028 SetWindowPos(window
, 0 /* InsertAfter, ignored */,
1029 0, 0, 0, 0, /* Pos, Size, ignored */
1030 SWP_FRAMECHANGED
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
);
1033 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1034 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice
*iface
,
1035 WINED3DPRESENT_PARAMETERS
*pPresentationParameters
, IWineD3DSwapChain
**ppSwapChain
,
1036 IUnknown
*parent
, WINED3DSURFTYPE surface_type
)
1038 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1041 IWineD3DSwapChainImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1043 BOOL displaymode_set
= FALSE
;
1044 WINED3DDISPLAYMODE Mode
;
1045 const struct GlPixelFormatDesc
*format_desc
;
1048 TRACE("(%p) : Created Additional Swap Chain\n", This
);
1050 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1051 * does a device hold a reference to a swap chain giving them a lifetime of the device
1052 * or does the swap chain notify the device of its destruction.
1053 *******************************/
1055 /* Check the params */
1056 if(pPresentationParameters
->BackBufferCount
> WINED3DPRESENT_BACK_BUFFER_MAX
) {
1057 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters
->BackBufferCount
);
1058 return WINED3DERR_INVALIDCALL
;
1059 } else if (pPresentationParameters
->BackBufferCount
> 1) {
1060 FIXME("The app requests more than one back buffer, this can't be supported properly. Please configure the application to use double buffering(=1 back buffer) if possible\n");
1063 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1066 ERR("Out of memory\n");
1067 *ppSwapChain
= NULL
;
1068 return WINED3DERR_OUTOFVIDEOMEMORY
;
1071 switch(surface_type
) {
1073 object
->lpVtbl
= &IWineGDISwapChain_Vtbl
;
1075 case SURFACE_OPENGL
:
1076 object
->lpVtbl
= &IWineD3DSwapChain_Vtbl
;
1078 case SURFACE_UNKNOWN
:
1079 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1080 HeapFree(GetProcessHeap(), 0, object
);
1081 return WINED3DERR_INVALIDCALL
;
1083 object
->wineD3DDevice
= This
;
1084 object
->parent
= parent
;
1087 *ppSwapChain
= (IWineD3DSwapChain
*)object
;
1089 /*********************
1090 * Lookup the window Handle and the relating X window handle
1091 ********************/
1093 /* Setup hwnd we are using, plus which display this equates to */
1094 object
->win_handle
= pPresentationParameters
->hDeviceWindow
;
1095 if (!object
->win_handle
) {
1096 object
->win_handle
= This
->createParms
.hFocusWindow
;
1098 if(!pPresentationParameters
->Windowed
&& object
->win_handle
) {
1099 IWineD3DDeviceImpl_SetupFullscreenWindow(iface
, object
->win_handle
,
1100 pPresentationParameters
->BackBufferWidth
,
1101 pPresentationParameters
->BackBufferHeight
);
1104 hDc
= GetDC(object
->win_handle
);
1105 TRACE("Using hDc %p\n", hDc
);
1108 WARN("Failed to get a HDc for Window %p\n", object
->win_handle
);
1109 return WINED3DERR_NOTAVAILABLE
;
1112 /* Get info on the current display setup */
1113 IWineD3D_GetAdapterDisplayMode(This
->wined3d
, This
->adapter
->ordinal
, &Mode
);
1114 object
->orig_width
= Mode
.Width
;
1115 object
->orig_height
= Mode
.Height
;
1116 object
->orig_fmt
= Mode
.Format
;
1117 format_desc
= getFormatDescEntry(Mode
.Format
, &This
->adapter
->gl_info
);
1119 GetClientRect(object
->win_handle
, &client_rect
);
1120 if (pPresentationParameters
->Windowed
&&
1121 ((pPresentationParameters
->BackBufferWidth
== 0) ||
1122 (pPresentationParameters
->BackBufferHeight
== 0) ||
1123 (pPresentationParameters
->BackBufferFormat
== WINED3DFMT_UNKNOWN
))) {
1125 if (pPresentationParameters
->BackBufferWidth
== 0) {
1126 pPresentationParameters
->BackBufferWidth
= client_rect
.right
;
1127 TRACE("Updating width to %d\n", pPresentationParameters
->BackBufferWidth
);
1129 if (pPresentationParameters
->BackBufferHeight
== 0) {
1130 pPresentationParameters
->BackBufferHeight
= client_rect
.bottom
;
1131 TRACE("Updating height to %d\n", pPresentationParameters
->BackBufferHeight
);
1133 if (pPresentationParameters
->BackBufferFormat
== WINED3DFMT_UNKNOWN
) {
1134 pPresentationParameters
->BackBufferFormat
= object
->orig_fmt
;
1135 TRACE("Updating format to %s\n", debug_d3dformat(object
->orig_fmt
));
1139 if(wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
)
1141 if(pPresentationParameters
->BackBufferWidth
!= client_rect
.right
||
1142 pPresentationParameters
->BackBufferHeight
!= client_rect
.bottom
)
1144 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
1145 pPresentationParameters
->BackBufferWidth
,
1146 pPresentationParameters
->BackBufferHeight
,
1147 client_rect
.right
, client_rect
.bottom
);
1148 object
->render_to_fbo
= TRUE
;
1152 TRACE("Rendering directly to GL_BACK\n");
1156 /* Put the correct figures in the presentation parameters */
1157 TRACE("Copying across presentation parameters\n");
1158 object
->presentParms
= *pPresentationParameters
;
1160 TRACE("calling rendertarget CB\n");
1161 hr
= IWineD3DDeviceParent_CreateRenderTarget(This
->device_parent
, parent
,
1162 object
->presentParms
.BackBufferWidth
, object
->presentParms
.BackBufferHeight
,
1163 object
->presentParms
.BackBufferFormat
, object
->presentParms
.MultiSampleType
,
1164 object
->presentParms
.MultiSampleQuality
, TRUE
/* Lockable */, &object
->frontBuffer
);
1165 if (SUCCEEDED(hr
)) {
1166 IWineD3DSurface_SetContainer(object
->frontBuffer
, (IWineD3DBase
*)object
);
1167 ((IWineD3DSurfaceImpl
*)object
->frontBuffer
)->Flags
|= SFLAG_SWAPCHAIN
;
1168 if(surface_type
== SURFACE_OPENGL
) {
1169 IWineD3DSurface_ModifyLocation(object
->frontBuffer
, SFLAG_INDRAWABLE
, TRUE
);
1172 ERR("Failed to create the front buffer\n");
1176 /*********************
1177 * Windowed / Fullscreen
1178 *******************/
1181 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1182 * so we should really check to see if there is a fullscreen swapchain already
1183 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1184 **************************************/
1186 if (!pPresentationParameters
->Windowed
) {
1187 WINED3DDISPLAYMODE mode
;
1190 /* Change the display settings */
1191 mode
.Width
= pPresentationParameters
->BackBufferWidth
;
1192 mode
.Height
= pPresentationParameters
->BackBufferHeight
;
1193 mode
.Format
= pPresentationParameters
->BackBufferFormat
;
1194 mode
.RefreshRate
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
1196 IWineD3DDevice_SetDisplayMode(iface
, 0, &mode
);
1197 displaymode_set
= TRUE
;
1201 * Create an opengl context for the display visual
1202 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1203 * use different properties after that point in time. FIXME: How to handle when requested format
1204 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1205 * it chooses is identical to the one already being used!
1206 **********************************/
1207 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1209 object
->context
= HeapAlloc(GetProcessHeap(), 0, sizeof(object
->context
));
1210 if(!object
->context
) {
1211 ERR("Failed to create the context array\n");
1215 object
->num_contexts
= 1;
1217 if (surface_type
== SURFACE_OPENGL
)
1219 object
->context
[0] = context_create(This
, (IWineD3DSurfaceImpl
*)object
->frontBuffer
,
1220 object
->win_handle
, FALSE
/* pbuffer */, pPresentationParameters
);
1221 if (!object
->context
[0]) {
1222 ERR("Failed to create a new context\n");
1223 hr
= WINED3DERR_NOTAVAILABLE
;
1226 TRACE("Context created (HWND=%p, glContext=%p)\n",
1227 object
->win_handle
, object
->context
[0]->glCtx
);
1229 object
->context
[0]->render_offscreen
= object
->render_to_fbo
;
1233 object
->context
[0] = NULL
;
1236 /*********************
1237 * Create the back, front and stencil buffers
1238 *******************/
1239 if(object
->presentParms
.BackBufferCount
> 0) {
1242 object
->backBuffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface
*) * object
->presentParms
.BackBufferCount
);
1243 if(!object
->backBuffer
) {
1244 ERR("Out of memory\n");
1249 for(i
= 0; i
< object
->presentParms
.BackBufferCount
; i
++) {
1250 TRACE("calling rendertarget CB\n");
1251 hr
= IWineD3DDeviceParent_CreateRenderTarget(This
->device_parent
, parent
,
1252 object
->presentParms
.BackBufferWidth
, object
->presentParms
.BackBufferHeight
,
1253 object
->presentParms
.BackBufferFormat
, object
->presentParms
.MultiSampleType
,
1254 object
->presentParms
.MultiSampleQuality
, TRUE
/* Lockable */, &object
->backBuffer
[i
]);
1256 IWineD3DSurface_SetContainer(object
->backBuffer
[i
], (IWineD3DBase
*)object
);
1257 ((IWineD3DSurfaceImpl
*)object
->backBuffer
[i
])->Flags
|= SFLAG_SWAPCHAIN
;
1259 ERR("Cannot create new back buffer\n");
1262 if(surface_type
== SURFACE_OPENGL
) {
1264 glDrawBuffer(GL_BACK
);
1265 checkGLcall("glDrawBuffer(GL_BACK)");
1270 object
->backBuffer
= NULL
;
1272 /* Single buffering - draw to front buffer */
1273 if(surface_type
== SURFACE_OPENGL
) {
1275 glDrawBuffer(GL_FRONT
);
1276 checkGLcall("glDrawBuffer(GL_FRONT)");
1281 if (object
->context
[0]) context_release(object
->context
[0]);
1283 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1284 if (pPresentationParameters
->EnableAutoDepthStencil
&& surface_type
== SURFACE_OPENGL
) {
1285 TRACE("Creating depth stencil buffer\n");
1286 if (This
->auto_depth_stencil_buffer
== NULL
) {
1287 hr
= IWineD3DDeviceParent_CreateDepthStencilSurface(This
->device_parent
, parent
,
1288 object
->presentParms
.BackBufferWidth
, object
->presentParms
.BackBufferHeight
,
1289 object
->presentParms
.AutoDepthStencilFormat
, object
->presentParms
.MultiSampleType
,
1290 object
->presentParms
.MultiSampleQuality
, FALSE
/* FIXME: Discard */,
1291 &This
->auto_depth_stencil_buffer
);
1292 if (SUCCEEDED(hr
)) {
1293 IWineD3DSurface_SetContainer(This
->auto_depth_stencil_buffer
, 0);
1295 ERR("Failed to create the auto depth stencil\n");
1301 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain
*) object
, &object
->orig_gamma
);
1303 TRACE("Created swapchain %p\n", object
);
1304 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object
->frontBuffer
, object
->backBuffer
? object
->backBuffer
[0] : NULL
, pPresentationParameters
->EnableAutoDepthStencil
);
1308 if (displaymode_set
) {
1312 SetRect(&clip_rc
, 0, 0, object
->orig_width
, object
->orig_height
);
1315 /* Change the display settings */
1316 memset(&devmode
, 0, sizeof(devmode
));
1317 devmode
.dmSize
= sizeof(devmode
);
1318 devmode
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
1319 devmode
.dmBitsPerPel
= format_desc
->byte_count
* 8;
1320 devmode
.dmPelsWidth
= object
->orig_width
;
1321 devmode
.dmPelsHeight
= object
->orig_height
;
1322 ChangeDisplaySettingsExW(This
->adapter
->DeviceName
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
);
1325 if (object
->backBuffer
) {
1327 for(i
= 0; i
< object
->presentParms
.BackBufferCount
; i
++) {
1328 if (object
->backBuffer
[i
]) IWineD3DSurface_Release(object
->backBuffer
[i
]);
1330 HeapFree(GetProcessHeap(), 0, object
->backBuffer
);
1331 object
->backBuffer
= NULL
;
1333 if(object
->context
&& object
->context
[0])
1335 context_release(object
->context
[0]);
1336 context_destroy(This
, object
->context
[0]);
1338 if (object
->frontBuffer
) IWineD3DSurface_Release(object
->frontBuffer
);
1339 HeapFree(GetProcessHeap(), 0, object
);
1343 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1344 static UINT WINAPI
IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice
*iface
) {
1345 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1346 TRACE("(%p)\n", This
);
1348 return This
->NumberOfSwapChains
;
1351 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice
*iface
, UINT iSwapChain
, IWineD3DSwapChain
**pSwapChain
) {
1352 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1353 TRACE("(%p) : swapchain %d\n", This
, iSwapChain
);
1355 if(iSwapChain
< This
->NumberOfSwapChains
) {
1356 *pSwapChain
= This
->swapchains
[iSwapChain
];
1357 IWineD3DSwapChain_AddRef(*pSwapChain
);
1358 TRACE("(%p) returning %p\n", This
, *pSwapChain
);
1361 TRACE("Swapchain out of range\n");
1363 return WINED3DERR_INVALIDCALL
;
1367 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice
*iface
,
1368 IWineD3DVertexDeclaration
**declaration
, IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
,
1369 const WINED3DVERTEXELEMENT
*elements
, UINT element_count
)
1371 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1372 IWineD3DVertexDeclarationImpl
*object
= NULL
;
1375 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1376 iface
, declaration
, parent
, elements
, element_count
);
1378 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1381 ERR("Failed to allocate vertex declaration memory.\n");
1382 return E_OUTOFMEMORY
;
1385 hr
= vertexdeclaration_init(object
, This
, elements
, element_count
, parent
, parent_ops
);
1388 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr
);
1389 HeapFree(GetProcessHeap(), 0, object
);
1393 TRACE("Created vertex declaration %p.\n", object
);
1394 *declaration
= (IWineD3DVertexDeclaration
*)object
;
1399 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl
*This
, /* For the GL info, which has the type table */
1400 DWORD fvf
, WINED3DVERTEXELEMENT
** ppVertexElements
) {
1402 unsigned int idx
, idx2
;
1403 unsigned int offset
;
1404 BOOL has_pos
= (fvf
& WINED3DFVF_POSITION_MASK
) != 0;
1405 BOOL has_blend
= (fvf
& WINED3DFVF_XYZB5
) > WINED3DFVF_XYZRHW
;
1406 BOOL has_blend_idx
= has_blend
&&
1407 (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB5
) ||
1408 (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
) ||
1409 (fvf
& WINED3DFVF_LASTBETA_UBYTE4
));
1410 BOOL has_normal
= (fvf
& WINED3DFVF_NORMAL
) != 0;
1411 BOOL has_psize
= (fvf
& WINED3DFVF_PSIZE
) != 0;
1412 BOOL has_diffuse
= (fvf
& WINED3DFVF_DIFFUSE
) != 0;
1413 BOOL has_specular
= (fvf
& WINED3DFVF_SPECULAR
) !=0;
1415 DWORD num_textures
= (fvf
& WINED3DFVF_TEXCOUNT_MASK
) >> WINED3DFVF_TEXCOUNT_SHIFT
;
1416 DWORD texcoords
= (fvf
& 0xFFFF0000) >> 16;
1417 WINED3DVERTEXELEMENT
*elements
= NULL
;
1420 DWORD num_blends
= 1 + (((fvf
& WINED3DFVF_XYZB5
) - WINED3DFVF_XYZB1
) >> 1);
1421 if (has_blend_idx
) num_blends
--;
1423 /* Compute declaration size */
1424 size
= has_pos
+ (has_blend
&& num_blends
> 0) + has_blend_idx
+ has_normal
+
1425 has_psize
+ has_diffuse
+ has_specular
+ num_textures
;
1427 /* convert the declaration */
1428 elements
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WINED3DVERTEXELEMENT
));
1429 if (!elements
) return ~0U;
1433 if (!has_blend
&& (fvf
& WINED3DFVF_XYZRHW
)) {
1434 elements
[idx
].format
= WINED3DFMT_R32G32B32A32_FLOAT
;
1435 elements
[idx
].usage
= WINED3DDECLUSAGE_POSITIONT
;
1437 else if ((fvf
& WINED3DFVF_XYZW
) == WINED3DFVF_XYZW
) {
1438 elements
[idx
].format
= WINED3DFMT_R32G32B32A32_FLOAT
;
1439 elements
[idx
].usage
= WINED3DDECLUSAGE_POSITION
;
1442 elements
[idx
].format
= WINED3DFMT_R32G32B32_FLOAT
;
1443 elements
[idx
].usage
= WINED3DDECLUSAGE_POSITION
;
1445 elements
[idx
].usage_idx
= 0;
1448 if (has_blend
&& (num_blends
> 0)) {
1449 if (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB2
) && (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
))
1450 elements
[idx
].format
= WINED3DFMT_B8G8R8A8_UNORM
;
1452 switch(num_blends
) {
1453 case 1: elements
[idx
].format
= WINED3DFMT_R32_FLOAT
; break;
1454 case 2: elements
[idx
].format
= WINED3DFMT_R32G32_FLOAT
; break;
1455 case 3: elements
[idx
].format
= WINED3DFMT_R32G32B32_FLOAT
; break;
1456 case 4: elements
[idx
].format
= WINED3DFMT_R32G32B32A32_FLOAT
; break;
1458 ERR("Unexpected amount of blend values: %u\n", num_blends
);
1461 elements
[idx
].usage
= WINED3DDECLUSAGE_BLENDWEIGHT
;
1462 elements
[idx
].usage_idx
= 0;
1465 if (has_blend_idx
) {
1466 if (fvf
& WINED3DFVF_LASTBETA_UBYTE4
||
1467 (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB2
) && (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
)))
1468 elements
[idx
].format
= WINED3DFMT_R8G8B8A8_UINT
;
1469 else if (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
)
1470 elements
[idx
].format
= WINED3DFMT_B8G8R8A8_UNORM
;
1472 elements
[idx
].format
= WINED3DFMT_R32_FLOAT
;
1473 elements
[idx
].usage
= WINED3DDECLUSAGE_BLENDINDICES
;
1474 elements
[idx
].usage_idx
= 0;
1478 elements
[idx
].format
= WINED3DFMT_R32G32B32_FLOAT
;
1479 elements
[idx
].usage
= WINED3DDECLUSAGE_NORMAL
;
1480 elements
[idx
].usage_idx
= 0;
1484 elements
[idx
].format
= WINED3DFMT_R32_FLOAT
;
1485 elements
[idx
].usage
= WINED3DDECLUSAGE_PSIZE
;
1486 elements
[idx
].usage_idx
= 0;
1490 elements
[idx
].format
= WINED3DFMT_B8G8R8A8_UNORM
;
1491 elements
[idx
].usage
= WINED3DDECLUSAGE_COLOR
;
1492 elements
[idx
].usage_idx
= 0;
1496 elements
[idx
].format
= WINED3DFMT_B8G8R8A8_UNORM
;
1497 elements
[idx
].usage
= WINED3DDECLUSAGE_COLOR
;
1498 elements
[idx
].usage_idx
= 1;
1501 for (idx2
= 0; idx2
< num_textures
; idx2
++) {
1502 unsigned int numcoords
= (texcoords
>> (idx2
*2)) & 0x03;
1503 switch (numcoords
) {
1504 case WINED3DFVF_TEXTUREFORMAT1
:
1505 elements
[idx
].format
= WINED3DFMT_R32_FLOAT
;
1507 case WINED3DFVF_TEXTUREFORMAT2
:
1508 elements
[idx
].format
= WINED3DFMT_R32G32_FLOAT
;
1510 case WINED3DFVF_TEXTUREFORMAT3
:
1511 elements
[idx
].format
= WINED3DFMT_R32G32B32_FLOAT
;
1513 case WINED3DFVF_TEXTUREFORMAT4
:
1514 elements
[idx
].format
= WINED3DFMT_R32G32B32A32_FLOAT
;
1517 elements
[idx
].usage
= WINED3DDECLUSAGE_TEXCOORD
;
1518 elements
[idx
].usage_idx
= idx2
;
1522 /* Now compute offsets, and initialize the rest of the fields */
1523 for (idx
= 0, offset
= 0; idx
< size
; ++idx
)
1525 const struct GlPixelFormatDesc
*format_desc
= getFormatDescEntry(elements
[idx
].format
, &This
->adapter
->gl_info
);
1526 elements
[idx
].input_slot
= 0;
1527 elements
[idx
].method
= WINED3DDECLMETHOD_DEFAULT
;
1528 elements
[idx
].offset
= offset
;
1529 offset
+= format_desc
->component_count
* format_desc
->component_size
;
1532 *ppVertexElements
= elements
;
1536 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice
*iface
,
1537 IWineD3DVertexDeclaration
**declaration
, IUnknown
*parent
,
1538 const struct wined3d_parent_ops
*parent_ops
, DWORD fvf
)
1540 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1541 WINED3DVERTEXELEMENT
*elements
;
1545 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface
, declaration
, parent
, fvf
);
1547 size
= ConvertFvfToDeclaration(This
, fvf
, &elements
);
1548 if (size
== ~0U) return E_OUTOFMEMORY
;
1550 hr
= IWineD3DDevice_CreateVertexDeclaration(iface
, declaration
, parent
, parent_ops
, elements
, size
);
1551 HeapFree(GetProcessHeap(), 0, elements
);
1555 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice
*iface
,
1556 const DWORD
*pFunction
, const struct wined3d_shader_signature
*output_signature
,
1557 IWineD3DVertexShader
**ppVertexShader
, IUnknown
*parent
,
1558 const struct wined3d_parent_ops
*parent_ops
)
1560 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1561 IWineD3DVertexShaderImpl
*object
;
1564 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1567 ERR("Failed to allocate shader memory.\n");
1568 return E_OUTOFMEMORY
;
1571 hr
= vertexshader_init(object
, This
, pFunction
, output_signature
, parent
, parent_ops
);
1574 WARN("Failed to initialize vertex shader, hr %#x.\n", hr
);
1575 HeapFree(GetProcessHeap(), 0, object
);
1579 TRACE("Created vertex shader %p.\n", object
);
1580 *ppVertexShader
= (IWineD3DVertexShader
*)object
;
1585 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice
*iface
,
1586 const DWORD
*pFunction
, const struct wined3d_shader_signature
*output_signature
,
1587 IWineD3DPixelShader
**ppPixelShader
, IUnknown
*parent
,
1588 const struct wined3d_parent_ops
*parent_ops
)
1590 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1591 IWineD3DPixelShaderImpl
*object
;
1594 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1597 ERR("Failed to allocate shader memory.\n");
1598 return E_OUTOFMEMORY
;
1601 hr
= pixelshader_init(object
, This
, pFunction
, output_signature
, parent
, parent_ops
);
1604 WARN("Failed to initialize pixel shader, hr %#x.\n", hr
);
1605 HeapFree(GetProcessHeap(), 0, object
);
1609 TRACE("Created pixel shader %p.\n", object
);
1610 *ppPixelShader
= (IWineD3DPixelShader
*)object
;
1615 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice
*iface
, DWORD Flags
,
1616 const PALETTEENTRY
*PalEnt
, IWineD3DPalette
**Palette
, IUnknown
*Parent
)
1618 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1619 IWineD3DPaletteImpl
*object
;
1621 TRACE("(%p)->(%x, %p, %p, %p)\n", This
, Flags
, PalEnt
, Palette
, Parent
);
1623 /* Create the new object */
1624 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DPaletteImpl
));
1626 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1627 return E_OUTOFMEMORY
;
1630 object
->lpVtbl
= &IWineD3DPalette_Vtbl
;
1632 object
->Flags
= Flags
;
1633 object
->parent
= Parent
;
1634 object
->wineD3DDevice
= This
;
1635 object
->palNumEntries
= IWineD3DPaletteImpl_Size(Flags
);
1636 object
->hpal
= CreatePalette((const LOGPALETTE
*)&(object
->palVersion
));
1639 HeapFree( GetProcessHeap(), 0, object
);
1640 return E_OUTOFMEMORY
;
1643 hr
= IWineD3DPalette_SetEntries((IWineD3DPalette
*) object
, 0, 0, IWineD3DPaletteImpl_Size(Flags
), PalEnt
);
1645 IWineD3DPalette_Release((IWineD3DPalette
*) object
);
1649 *Palette
= (IWineD3DPalette
*) object
;
1654 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl
*This
, const char *filename
) {
1658 HDC dcb
= NULL
, dcs
= NULL
;
1659 WINEDDCOLORKEY colorkey
;
1661 hbm
= LoadImageA(NULL
, filename
, IMAGE_BITMAP
, 0, 0, LR_LOADFROMFILE
| LR_CREATEDIBSECTION
);
1664 GetObjectA(hbm
, sizeof(BITMAP
), &bm
);
1665 dcb
= CreateCompatibleDC(NULL
);
1667 SelectObject(dcb
, hbm
);
1671 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1672 * couldn't be loaded
1674 memset(&bm
, 0, sizeof(bm
));
1679 hr
= IWineD3DDevice_CreateSurface((IWineD3DDevice
*)This
, bm
.bmWidth
, bm
.bmHeight
, WINED3DFMT_B5G6R5_UNORM
, TRUE
,
1680 FALSE
, 0, &This
->logo_surface
, 0, WINED3DPOOL_DEFAULT
, WINED3DMULTISAMPLE_NONE
, 0, SURFACE_OPENGL
,
1681 NULL
, &wined3d_null_parent_ops
);
1683 ERR("Wine logo requested, but failed to create surface\n");
1688 hr
= IWineD3DSurface_GetDC(This
->logo_surface
, &dcs
);
1689 if(FAILED(hr
)) goto out
;
1690 BitBlt(dcs
, 0, 0, bm
.bmWidth
, bm
.bmHeight
, dcb
, 0, 0, SRCCOPY
);
1691 IWineD3DSurface_ReleaseDC(This
->logo_surface
, dcs
);
1693 colorkey
.dwColorSpaceLowValue
= 0;
1694 colorkey
.dwColorSpaceHighValue
= 0;
1695 IWineD3DSurface_SetColorKey(This
->logo_surface
, WINEDDCKEY_SRCBLT
, &colorkey
);
1697 /* Fill the surface with a white color to show that wined3d is there */
1698 IWineD3DDevice_ColorFill((IWineD3DDevice
*) This
, This
->logo_surface
, NULL
, 0xffffffff);
1711 /* Context activation is done by the caller. */
1712 static void create_dummy_textures(IWineD3DDeviceImpl
*This
)
1714 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
1716 /* Under DirectX you can have texture stage operations even if no texture is
1717 bound, whereas opengl will only do texture operations when a valid texture is
1718 bound. We emulate this by creating dummy textures and binding them to each
1719 texture stage, but disable all stages by default. Hence if a stage is enabled
1720 then the default texture will kick in until replaced by a SetTexture call */
1723 if (gl_info
->supported
[APPLE_CLIENT_STORAGE
])
1725 /* The dummy texture does not have client storage backing */
1726 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
1727 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1730 for (i
= 0; i
< gl_info
->limits
.textures
; ++i
)
1732 GLubyte white
= 255;
1734 /* Make appropriate texture active */
1735 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
+ i
));
1736 checkGLcall("glActiveTextureARB");
1738 /* Generate an opengl texture name */
1739 glGenTextures(1, &This
->dummyTextureName
[i
]);
1740 checkGLcall("glGenTextures");
1741 TRACE("Dummy Texture %d given name %d\n", i
, This
->dummyTextureName
[i
]);
1743 /* Generate a dummy 2d texture (not using 1d because they cause many
1744 * DRI drivers fall back to sw) */
1745 glBindTexture(GL_TEXTURE_2D
, This
->dummyTextureName
[i
]);
1746 checkGLcall("glBindTexture");
1748 glTexImage2D(GL_TEXTURE_2D
, 0, GL_LUMINANCE
, 1, 1, 0, GL_LUMINANCE
, GL_UNSIGNED_BYTE
, &white
);
1749 checkGLcall("glTexImage2D");
1752 if (gl_info
->supported
[APPLE_CLIENT_STORAGE
])
1754 /* Reenable because if supported it is enabled by default */
1755 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
1756 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1762 static HRESULT WINAPI
IWineD3DDeviceImpl_Init3D(IWineD3DDevice
*iface
,
1763 WINED3DPRESENT_PARAMETERS
*pPresentationParameters
)
1765 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1766 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
1767 IWineD3DSwapChainImpl
*swapchain
= NULL
;
1768 struct wined3d_context
*context
;
1773 TRACE("(%p)->(%p)\n", This
, pPresentationParameters
);
1775 if(This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
1776 if(!This
->adapter
->opengl
) return WINED3DERR_INVALIDCALL
;
1778 /* TODO: Test if OpenGL is compiled in and loaded */
1780 TRACE("(%p) : Creating stateblock\n", This
);
1781 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1782 hr
= IWineD3DDevice_CreateStateBlock(iface
,
1784 (IWineD3DStateBlock
**)&This
->stateBlock
,
1786 if (WINED3D_OK
!= hr
) { /* Note: No parent needed for initial internal stateblock */
1787 WARN("Failed to create stateblock\n");
1790 TRACE("(%p) : Created stateblock (%p)\n", This
, This
->stateBlock
);
1791 This
->updateStateBlock
= This
->stateBlock
;
1792 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
1794 This
->render_targets
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
1795 sizeof(IWineD3DSurface
*) * gl_info
->limits
.buffers
);
1796 This
->draw_buffers
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
1797 sizeof(GLenum
) * gl_info
->limits
.buffers
);
1799 This
->NumberOfPalettes
= 1;
1800 This
->palettes
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(PALETTEENTRY
*));
1801 if(!This
->palettes
|| !This
->render_targets
|| !This
->draw_buffers
) {
1802 ERR("Out of memory!\n");
1806 This
->palettes
[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY
) * 256);
1807 if(!This
->palettes
[0]) {
1808 ERR("Out of memory!\n");
1812 for (i
= 0; i
< 256; ++i
) {
1813 This
->palettes
[0][i
].peRed
= 0xFF;
1814 This
->palettes
[0][i
].peGreen
= 0xFF;
1815 This
->palettes
[0][i
].peBlue
= 0xFF;
1816 This
->palettes
[0][i
].peFlags
= 0xFF;
1818 This
->currentPalette
= 0;
1820 /* Initialize the texture unit mapping to a 1:1 mapping */
1821 for (state
= 0; state
< MAX_COMBINED_SAMPLERS
; ++state
)
1823 if (state
< gl_info
->limits
.fragment_samplers
)
1825 This
->texUnitMap
[state
] = state
;
1826 This
->rev_tex_unit_map
[state
] = state
;
1828 This
->texUnitMap
[state
] = WINED3D_UNMAPPED_STAGE
;
1829 This
->rev_tex_unit_map
[state
] = WINED3D_UNMAPPED_STAGE
;
1833 /* Setup the implicit swapchain. This also initializes a context. */
1834 TRACE("Creating implicit swapchain\n");
1835 hr
= IWineD3DDeviceParent_CreateSwapChain(This
->device_parent
,
1836 pPresentationParameters
, (IWineD3DSwapChain
**)&swapchain
);
1839 WARN("Failed to create implicit swapchain\n");
1843 This
->NumberOfSwapChains
= 1;
1844 This
->swapchains
= HeapAlloc(GetProcessHeap(), 0, This
->NumberOfSwapChains
* sizeof(IWineD3DSwapChain
*));
1845 if(!This
->swapchains
) {
1846 ERR("Out of memory!\n");
1849 This
->swapchains
[0] = (IWineD3DSwapChain
*) swapchain
;
1851 if(swapchain
->backBuffer
&& swapchain
->backBuffer
[0]) {
1852 TRACE("Setting rendertarget to %p\n", swapchain
->backBuffer
);
1853 This
->render_targets
[0] = swapchain
->backBuffer
[0];
1856 TRACE("Setting rendertarget to %p\n", swapchain
->frontBuffer
);
1857 This
->render_targets
[0] = swapchain
->frontBuffer
;
1859 IWineD3DSurface_AddRef(This
->render_targets
[0]);
1861 /* Depth Stencil support */
1862 This
->stencilBufferTarget
= This
->auto_depth_stencil_buffer
;
1863 if (NULL
!= This
->stencilBufferTarget
) {
1864 IWineD3DSurface_AddRef(This
->stencilBufferTarget
);
1867 hr
= This
->shader_backend
->shader_alloc_private(iface
);
1869 TRACE("Shader private data couldn't be allocated\n");
1872 hr
= This
->frag_pipe
->alloc_private(iface
);
1874 TRACE("Fragment pipeline private data couldn't be allocated\n");
1877 hr
= This
->blitter
->alloc_private(iface
);
1879 TRACE("Blitter private data couldn't be allocated\n");
1883 /* Set up some starting GL setup */
1885 /* Setup all the devices defaults */
1886 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock
*)This
->stateBlock
);
1888 context
= context_acquire(This
, swapchain
->frontBuffer
, CTXUSAGE_RESOURCELOAD
);
1890 create_dummy_textures(This
);
1894 /* Initialize the current view state */
1895 This
->view_ident
= 1;
1896 This
->contexts
[0]->last_was_rhw
= 0;
1897 glGetIntegerv(GL_MAX_LIGHTS
, &This
->maxConcurrentLights
);
1898 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1900 switch(wined3d_settings
.offscreen_rendering_mode
) {
1902 This
->offscreenBuffer
= GL_COLOR_ATTACHMENT0
;
1906 This
->offscreenBuffer
= GL_BACK
;
1909 case ORM_BACKBUFFER
:
1911 if (context_get_current()->aux_buffers
> 0)
1913 TRACE("Using auxilliary buffer for offscreen rendering\n");
1914 This
->offscreenBuffer
= GL_AUX0
;
1916 TRACE("Using back buffer for offscreen rendering\n");
1917 This
->offscreenBuffer
= GL_BACK
;
1922 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This
, This
);
1925 context_release(context
);
1927 /* Clear the screen */
1928 IWineD3DDevice_Clear((IWineD3DDevice
*) This
, 0, NULL
,
1929 WINED3DCLEAR_TARGET
| pPresentationParameters
->EnableAutoDepthStencil
? WINED3DCLEAR_ZBUFFER
| WINED3DCLEAR_STENCIL
: 0,
1932 This
->d3d_initialized
= TRUE
;
1934 if(wined3d_settings
.logo
) {
1935 IWineD3DDeviceImpl_LoadLogo(This
, wined3d_settings
.logo
);
1937 This
->highest_dirty_ps_const
= 0;
1938 This
->highest_dirty_vs_const
= 0;
1942 HeapFree(GetProcessHeap(), 0, This
->render_targets
);
1943 HeapFree(GetProcessHeap(), 0, This
->draw_buffers
);
1944 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
1945 This
->NumberOfSwapChains
= 0;
1946 if(This
->palettes
) {
1947 HeapFree(GetProcessHeap(), 0, This
->palettes
[0]);
1948 HeapFree(GetProcessHeap(), 0, This
->palettes
);
1950 This
->NumberOfPalettes
= 0;
1952 IWineD3DSwapChain_Release( (IWineD3DSwapChain
*) swapchain
);
1954 if(This
->stateBlock
) {
1955 IWineD3DStateBlock_Release((IWineD3DStateBlock
*) This
->stateBlock
);
1956 This
->stateBlock
= NULL
;
1958 if (This
->blit_priv
) {
1959 This
->blitter
->free_private(iface
);
1961 if (This
->fragment_priv
) {
1962 This
->frag_pipe
->free_private(iface
);
1964 if (This
->shader_priv
) {
1965 This
->shader_backend
->shader_free_private(iface
);
1970 static HRESULT WINAPI
IWineD3DDeviceImpl_InitGDI(IWineD3DDevice
*iface
,
1971 WINED3DPRESENT_PARAMETERS
*pPresentationParameters
)
1973 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1974 IWineD3DSwapChainImpl
*swapchain
= NULL
;
1977 /* Setup the implicit swapchain */
1978 TRACE("Creating implicit swapchain\n");
1979 hr
= IWineD3DDeviceParent_CreateSwapChain(This
->device_parent
,
1980 pPresentationParameters
, (IWineD3DSwapChain
**)&swapchain
);
1983 WARN("Failed to create implicit swapchain\n");
1987 This
->NumberOfSwapChains
= 1;
1988 This
->swapchains
= HeapAlloc(GetProcessHeap(), 0, This
->NumberOfSwapChains
* sizeof(IWineD3DSwapChain
*));
1989 if(!This
->swapchains
) {
1990 ERR("Out of memory!\n");
1993 This
->swapchains
[0] = (IWineD3DSwapChain
*) swapchain
;
1997 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
2001 static HRESULT WINAPI
device_unload_resource(IWineD3DResource
*resource
, void *ctx
)
2003 IWineD3DResource_UnLoad(resource
);
2004 IWineD3DResource_Release(resource
);
2008 static HRESULT WINAPI
IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice
*iface
,
2009 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain
)
2011 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2012 const struct wined3d_gl_info
*gl_info
;
2013 struct wined3d_context
*context
;
2016 TRACE("(%p)\n", This
);
2018 if(!This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
2020 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2021 * it was created. Thus make sure a context is active for the glDelete* calls
2023 context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
2024 gl_info
= context
->gl_info
;
2026 if(This
->logo_surface
) IWineD3DSurface_Release(This
->logo_surface
);
2028 /* Unload resources */
2029 IWineD3DDevice_EnumResources(iface
, device_unload_resource
, NULL
);
2031 TRACE("Deleting high order patches\n");
2032 for(i
= 0; i
< PATCHMAP_SIZE
; i
++) {
2033 struct list
*e1
, *e2
;
2034 struct WineD3DRectPatch
*patch
;
2035 LIST_FOR_EACH_SAFE(e1
, e2
, &This
->patches
[i
]) {
2036 patch
= LIST_ENTRY(e1
, struct WineD3DRectPatch
, entry
);
2037 IWineD3DDevice_DeletePatch(iface
, patch
->Handle
);
2041 /* Delete the palette conversion shader if it is around */
2042 if(This
->paletteConversionShader
) {
2044 GL_EXTCALL(glDeleteProgramsARB(1, &This
->paletteConversionShader
));
2046 This
->paletteConversionShader
= 0;
2049 /* Delete the pbuffer context if there is any */
2050 if(This
->pbufferContext
) context_destroy(This
, This
->pbufferContext
);
2052 /* Delete the mouse cursor texture */
2053 if(This
->cursorTexture
) {
2055 glDeleteTextures(1, &This
->cursorTexture
);
2057 This
->cursorTexture
= 0;
2060 for (sampler
= 0; sampler
< MAX_FRAGMENT_SAMPLERS
; ++sampler
) {
2061 IWineD3DDevice_SetTexture(iface
, sampler
, NULL
);
2063 for (sampler
= 0; sampler
< MAX_VERTEX_SAMPLERS
; ++sampler
) {
2064 IWineD3DDevice_SetTexture(iface
, WINED3DVERTEXTEXTURESAMPLER0
+ sampler
, NULL
);
2067 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2068 * private data, it might contain opengl pointers
2070 if(This
->depth_blt_texture
) {
2072 glDeleteTextures(1, &This
->depth_blt_texture
);
2074 This
->depth_blt_texture
= 0;
2076 if (This
->depth_blt_rb
) {
2078 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &This
->depth_blt_rb
);
2080 This
->depth_blt_rb
= 0;
2081 This
->depth_blt_rb_w
= 0;
2082 This
->depth_blt_rb_h
= 0;
2085 /* Release the update stateblock */
2086 if(IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
) > 0){
2087 if(This
->updateStateBlock
!= This
->stateBlock
)
2088 FIXME("(%p) Something's still holding the Update stateblock\n",This
);
2090 This
->updateStateBlock
= NULL
;
2092 { /* because were not doing proper internal refcounts releasing the primary state block
2093 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2094 to set this->stateBlock = NULL; first */
2095 IWineD3DStateBlock
*stateBlock
= (IWineD3DStateBlock
*)This
->stateBlock
;
2096 This
->stateBlock
= NULL
;
2098 /* Release the stateblock */
2099 if(IWineD3DStateBlock_Release(stateBlock
) > 0){
2100 FIXME("(%p) Something's still holding the Update stateblock\n",This
);
2104 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2105 This
->blitter
->free_private(iface
);
2106 This
->frag_pipe
->free_private(iface
);
2107 This
->shader_backend
->shader_free_private(iface
);
2109 /* Release the buffers (with sanity checks)*/
2110 TRACE("Releasing the depth stencil buffer at %p\n", This
->stencilBufferTarget
);
2111 if(This
->stencilBufferTarget
!= NULL
&& (IWineD3DSurface_Release(This
->stencilBufferTarget
) >0)){
2112 if(This
->auto_depth_stencil_buffer
!= This
->stencilBufferTarget
)
2113 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This
);
2115 This
->stencilBufferTarget
= NULL
;
2117 TRACE("Releasing the render target at %p\n", This
->render_targets
[0]);
2118 if(IWineD3DSurface_Release(This
->render_targets
[0]) >0){
2119 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2121 TRACE("Setting rendertarget to NULL\n");
2122 This
->render_targets
[0] = NULL
;
2124 if (This
->auto_depth_stencil_buffer
) {
2125 if (IWineD3DSurface_Release(This
->auto_depth_stencil_buffer
) > 0)
2127 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This
);
2129 This
->auto_depth_stencil_buffer
= NULL
;
2132 context_release(context
);
2134 for(i
=0; i
< This
->NumberOfSwapChains
; i
++) {
2135 TRACE("Releasing the implicit swapchain %d\n", i
);
2136 if (D3DCB_DestroySwapChain(This
->swapchains
[i
]) > 0) {
2137 FIXME("(%p) Something's still holding the implicit swapchain\n", This
);
2141 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
2142 This
->swapchains
= NULL
;
2143 This
->NumberOfSwapChains
= 0;
2145 for (i
= 0; i
< This
->NumberOfPalettes
; i
++) HeapFree(GetProcessHeap(), 0, This
->palettes
[i
]);
2146 HeapFree(GetProcessHeap(), 0, This
->palettes
);
2147 This
->palettes
= NULL
;
2148 This
->NumberOfPalettes
= 0;
2150 HeapFree(GetProcessHeap(), 0, This
->render_targets
);
2151 HeapFree(GetProcessHeap(), 0, This
->draw_buffers
);
2152 This
->render_targets
= NULL
;
2153 This
->draw_buffers
= NULL
;
2155 This
->d3d_initialized
= FALSE
;
2159 static HRESULT WINAPI
IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice
*iface
, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain
) {
2160 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2163 for(i
=0; i
< This
->NumberOfSwapChains
; i
++) {
2164 TRACE("Releasing the implicit swapchain %d\n", i
);
2165 if (D3DCB_DestroySwapChain(This
->swapchains
[i
]) > 0) {
2166 FIXME("(%p) Something's still holding the implicit swapchain\n", This
);
2170 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
2171 This
->swapchains
= NULL
;
2172 This
->NumberOfSwapChains
= 0;
2176 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2177 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2178 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2180 * There is no way to deactivate thread safety once it is enabled.
2182 static void WINAPI
IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice
*iface
) {
2183 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2185 /*For now just store the flag(needed in case of ddraw) */
2186 This
->createParms
.BehaviorFlags
|= WINED3DCREATE_MULTITHREADED
;
2191 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
,
2192 const WINED3DDISPLAYMODE
* pMode
) {
2194 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2196 const struct GlPixelFormatDesc
*format_desc
= getFormatDescEntry(pMode
->Format
, &This
->adapter
->gl_info
);
2199 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This
, iSwapChain
, pMode
, pMode
->Width
, pMode
->Height
, pMode
->RefreshRate
, debug_d3dformat(pMode
->Format
));
2201 /* Resize the screen even without a window:
2202 * The app could have unset it with SetCooperativeLevel, but not called
2203 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2204 * but we don't have any hwnd
2207 memset(&devmode
, 0, sizeof(devmode
));
2208 devmode
.dmSize
= sizeof(devmode
);
2209 devmode
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
2210 devmode
.dmBitsPerPel
= format_desc
->byte_count
* 8;
2211 devmode
.dmPelsWidth
= pMode
->Width
;
2212 devmode
.dmPelsHeight
= pMode
->Height
;
2214 devmode
.dmDisplayFrequency
= pMode
->RefreshRate
;
2215 if (pMode
->RefreshRate
!= 0) {
2216 devmode
.dmFields
|= DM_DISPLAYFREQUENCY
;
2219 /* Only change the mode if necessary */
2220 if( (This
->ddraw_width
== pMode
->Width
) &&
2221 (This
->ddraw_height
== pMode
->Height
) &&
2222 (This
->ddraw_format
== pMode
->Format
) &&
2223 (pMode
->RefreshRate
== 0) ) {
2227 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
);
2228 if (ret
!= DISP_CHANGE_SUCCESSFUL
) {
2229 if(devmode
.dmDisplayFrequency
!= 0) {
2230 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2231 devmode
.dmFields
&= ~DM_DISPLAYFREQUENCY
;
2232 devmode
.dmDisplayFrequency
= 0;
2233 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
) != DISP_CHANGE_SUCCESSFUL
;
2235 if(ret
!= DISP_CHANGE_SUCCESSFUL
) {
2236 return WINED3DERR_NOTAVAILABLE
;
2240 /* Store the new values */
2241 This
->ddraw_width
= pMode
->Width
;
2242 This
->ddraw_height
= pMode
->Height
;
2243 This
->ddraw_format
= pMode
->Format
;
2245 /* And finally clip mouse to our screen */
2246 SetRect(&clip_rc
, 0, 0, pMode
->Width
, pMode
->Height
);
2247 ClipCursor(&clip_rc
);
2252 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice
*iface
, IWineD3D
**ppD3D
) {
2253 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2254 *ppD3D
= This
->wined3d
;
2255 TRACE("Returning %p.\n", *ppD3D
);
2256 IWineD3D_AddRef(*ppD3D
);
2260 static UINT WINAPI
IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice
*iface
) {
2261 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2263 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This
,
2264 (This
->adapter
->TextureRam
/(1024*1024)),
2265 ((This
->adapter
->TextureRam
- This
->adapter
->UsedTextureRam
) / (1024*1024)));
2266 /* return simulated texture memory left */
2267 return (This
->adapter
->TextureRam
- This
->adapter
->UsedTextureRam
);
2271 * Get / Set Stream Source
2273 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice
*iface
, UINT StreamNumber
,
2274 IWineD3DBuffer
*pStreamData
, UINT OffsetInBytes
, UINT Stride
)
2276 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2277 IWineD3DBuffer
*oldSrc
;
2279 if (StreamNumber
>= MAX_STREAMS
) {
2280 WARN("Stream out of range %d\n", StreamNumber
);
2281 return WINED3DERR_INVALIDCALL
;
2282 } else if(OffsetInBytes
& 0x3) {
2283 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes
);
2284 return WINED3DERR_INVALIDCALL
;
2287 oldSrc
= This
->updateStateBlock
->streamSource
[StreamNumber
];
2288 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This
, StreamNumber
, oldSrc
, pStreamData
, OffsetInBytes
, Stride
);
2290 This
->updateStateBlock
->changed
.streamSource
|= 1 << StreamNumber
;
2292 if(oldSrc
== pStreamData
&&
2293 This
->updateStateBlock
->streamStride
[StreamNumber
] == Stride
&&
2294 This
->updateStateBlock
->streamOffset
[StreamNumber
] == OffsetInBytes
) {
2295 TRACE("Application is setting the old values over, nothing to do\n");
2299 This
->updateStateBlock
->streamSource
[StreamNumber
] = pStreamData
;
2301 This
->updateStateBlock
->streamStride
[StreamNumber
] = Stride
;
2302 This
->updateStateBlock
->streamOffset
[StreamNumber
] = OffsetInBytes
;
2305 /* Handle recording of state blocks */
2306 if (This
->isRecordingState
) {
2307 TRACE("Recording... not performing anything\n");
2308 if (pStreamData
) IWineD3DBuffer_AddRef(pStreamData
);
2309 if (oldSrc
) IWineD3DBuffer_Release(oldSrc
);
2313 if (pStreamData
!= NULL
) {
2314 InterlockedIncrement(&((struct wined3d_buffer
*)pStreamData
)->bind_count
);
2315 IWineD3DBuffer_AddRef(pStreamData
);
2317 if (oldSrc
!= NULL
) {
2318 InterlockedDecrement(&((struct wined3d_buffer
*)oldSrc
)->bind_count
);
2319 IWineD3DBuffer_Release(oldSrc
);
2322 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2327 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice
*iface
,
2328 UINT StreamNumber
, IWineD3DBuffer
**pStream
, UINT
*pOffset
, UINT
*pStride
)
2330 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2332 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This
, StreamNumber
,
2333 This
->stateBlock
->streamSource
[StreamNumber
],
2334 This
->stateBlock
->streamOffset
[StreamNumber
],
2335 This
->stateBlock
->streamStride
[StreamNumber
]);
2337 if (StreamNumber
>= MAX_STREAMS
) {
2338 WARN("Stream out of range %d\n", StreamNumber
);
2339 return WINED3DERR_INVALIDCALL
;
2341 *pStream
= This
->stateBlock
->streamSource
[StreamNumber
];
2342 *pStride
= This
->stateBlock
->streamStride
[StreamNumber
];
2344 *pOffset
= This
->stateBlock
->streamOffset
[StreamNumber
];
2347 if (*pStream
!= NULL
) {
2348 IWineD3DBuffer_AddRef(*pStream
); /* We have created a new reference to the VB */
2353 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT Divider
) {
2354 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2355 UINT oldFlags
= This
->updateStateBlock
->streamFlags
[StreamNumber
];
2356 UINT oldFreq
= This
->updateStateBlock
->streamFreq
[StreamNumber
];
2358 /* Verify input at least in d3d9 this is invalid*/
2359 if( (Divider
& WINED3DSTREAMSOURCE_INSTANCEDATA
) && (Divider
& WINED3DSTREAMSOURCE_INDEXEDDATA
)){
2360 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2361 return WINED3DERR_INVALIDCALL
;
2363 if( (Divider
& WINED3DSTREAMSOURCE_INSTANCEDATA
) && StreamNumber
== 0 ){
2364 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2365 return WINED3DERR_INVALIDCALL
;
2368 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2369 return WINED3DERR_INVALIDCALL
;
2372 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This
, StreamNumber
, Divider
);
2373 This
->updateStateBlock
->streamFlags
[StreamNumber
] = Divider
& (WINED3DSTREAMSOURCE_INSTANCEDATA
| WINED3DSTREAMSOURCE_INDEXEDDATA
);
2375 This
->updateStateBlock
->changed
.streamFreq
|= 1 << StreamNumber
;
2376 This
->updateStateBlock
->streamFreq
[StreamNumber
] = Divider
& 0x7FFFFF;
2378 if(This
->updateStateBlock
->streamFreq
[StreamNumber
] != oldFreq
||
2379 This
->updateStateBlock
->streamFlags
[StreamNumber
] != oldFlags
) {
2380 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2386 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT
* Divider
) {
2387 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2389 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This
, StreamNumber
, Divider
);
2390 *Divider
= This
->updateStateBlock
->streamFreq
[StreamNumber
] | This
->updateStateBlock
->streamFlags
[StreamNumber
];
2392 TRACE("(%p) : returning %d\n", This
, *Divider
);
2398 * Get / Set & Multiply Transform
2400 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE d3dts
, CONST WINED3DMATRIX
* lpmatrix
) {
2401 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2403 /* Most of this routine, comments included copied from ddraw tree initially: */
2404 TRACE("(%p) : Transform State=%s\n", This
, debug_d3dtstype(d3dts
));
2406 /* Handle recording of state blocks */
2407 if (This
->isRecordingState
) {
2408 TRACE("Recording... not performing anything\n");
2409 This
->updateStateBlock
->changed
.transform
[d3dts
>> 5] |= 1 << (d3dts
& 0x1f);
2410 This
->updateStateBlock
->transforms
[d3dts
] = *lpmatrix
;
2415 * If the new matrix is the same as the current one,
2416 * we cut off any further processing. this seems to be a reasonable
2417 * optimization because as was noticed, some apps (warcraft3 for example)
2418 * tend towards setting the same matrix repeatedly for some reason.
2420 * From here on we assume that the new matrix is different, wherever it matters.
2422 if (!memcmp(&This
->stateBlock
->transforms
[d3dts
].u
.m
[0][0], lpmatrix
, sizeof(WINED3DMATRIX
))) {
2423 TRACE("The app is setting the same matrix over again\n");
2426 conv_mat(lpmatrix
, &This
->stateBlock
->transforms
[d3dts
].u
.m
[0][0]);
2430 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2431 where ViewMat = Camera space, WorldMat = world space.
2433 In OpenGL, camera and world space is combined into GL_MODELVIEW
2434 matrix. The Projection matrix stay projection matrix.
2437 /* Capture the times we can just ignore the change for now */
2438 if (d3dts
== WINED3DTS_VIEW
) { /* handle the VIEW matrix */
2439 This
->view_ident
= !memcmp(lpmatrix
, identity
, 16 * sizeof(float));
2440 /* Handled by the state manager */
2443 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TRANSFORM(d3dts
));
2447 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, WINED3DMATRIX
* pMatrix
) {
2448 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2449 TRACE("(%p) : for Transform State %s\n", This
, debug_d3dtstype(State
));
2450 *pMatrix
= This
->stateBlock
->transforms
[State
];
2454 static HRESULT WINAPI
IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, CONST WINED3DMATRIX
* pMatrix
) {
2455 const WINED3DMATRIX
*mat
= NULL
;
2458 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2459 * below means it will be recorded in a state block change, but it
2460 * works regardless where it is recorded.
2461 * If this is found to be wrong, change to StateBlock.
2463 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2464 TRACE("(%p) : For state %s\n", This
, debug_d3dtstype(State
));
2466 if (State
<= HIGHEST_TRANSFORMSTATE
)
2468 mat
= &This
->updateStateBlock
->transforms
[State
];
2470 FIXME("Unhandled transform state!!\n");
2473 multiply_matrix(&temp
, mat
, pMatrix
);
2475 /* Apply change via set transform - will reapply to eg. lights this way */
2476 return IWineD3DDeviceImpl_SetTransform(iface
, State
, &temp
);
2482 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2483 you can reference any indexes you want as long as that number max are enabled at any
2484 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2485 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2486 but when recording, just build a chain pretty much of commands to be replayed. */
2488 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLight(IWineD3DDevice
*iface
, DWORD Index
, CONST WINED3DLIGHT
* pLight
) {
2490 struct wined3d_light_info
*object
= NULL
;
2491 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2494 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2495 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This
, Index
, pLight
, Hi
);
2497 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2501 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2502 return WINED3DERR_INVALIDCALL
;
2505 switch(pLight
->Type
) {
2506 case WINED3DLIGHT_POINT
:
2507 case WINED3DLIGHT_SPOT
:
2508 case WINED3DLIGHT_PARALLELPOINT
:
2509 case WINED3DLIGHT_GLSPOT
:
2510 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2513 if (pLight
->Attenuation0
< 0.0f
|| pLight
->Attenuation1
< 0.0f
|| pLight
->Attenuation2
< 0.0f
)
2515 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2516 return WINED3DERR_INVALIDCALL
;
2520 case WINED3DLIGHT_DIRECTIONAL
:
2521 /* Ignores attenuation */
2525 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2526 return WINED3DERR_INVALIDCALL
;
2529 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
])
2531 object
= LIST_ENTRY(e
, struct wined3d_light_info
, entry
);
2532 if(object
->OriginalIndex
== Index
) break;
2537 TRACE("Adding new light\n");
2538 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
2540 ERR("Out of memory error when allocating a light\n");
2541 return E_OUTOFMEMORY
;
2543 list_add_head(&This
->updateStateBlock
->lightMap
[Hi
], &object
->entry
);
2544 object
->glIndex
= -1;
2545 object
->OriginalIndex
= Index
;
2548 /* Initialize the object */
2549 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
,
2550 pLight
->Diffuse
.r
, pLight
->Diffuse
.g
, pLight
->Diffuse
.b
, pLight
->Diffuse
.a
,
2551 pLight
->Specular
.r
, pLight
->Specular
.g
, pLight
->Specular
.b
, pLight
->Specular
.a
,
2552 pLight
->Ambient
.r
, pLight
->Ambient
.g
, pLight
->Ambient
.b
, pLight
->Ambient
.a
);
2553 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight
->Position
.x
, pLight
->Position
.y
, pLight
->Position
.z
,
2554 pLight
->Direction
.x
, pLight
->Direction
.y
, pLight
->Direction
.z
);
2555 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight
->Range
, pLight
->Falloff
, pLight
->Theta
, pLight
->Phi
);
2557 /* Save away the information */
2558 object
->OriginalParms
= *pLight
;
2560 switch (pLight
->Type
) {
2561 case WINED3DLIGHT_POINT
:
2563 object
->lightPosn
[0] = pLight
->Position
.x
;
2564 object
->lightPosn
[1] = pLight
->Position
.y
;
2565 object
->lightPosn
[2] = pLight
->Position
.z
;
2566 object
->lightPosn
[3] = 1.0f
;
2567 object
->cutoff
= 180.0f
;
2571 case WINED3DLIGHT_DIRECTIONAL
:
2573 object
->lightPosn
[0] = -pLight
->Direction
.x
;
2574 object
->lightPosn
[1] = -pLight
->Direction
.y
;
2575 object
->lightPosn
[2] = -pLight
->Direction
.z
;
2576 object
->lightPosn
[3] = 0.0f
;
2577 object
->exponent
= 0.0f
;
2578 object
->cutoff
= 180.0f
;
2581 case WINED3DLIGHT_SPOT
:
2583 object
->lightPosn
[0] = pLight
->Position
.x
;
2584 object
->lightPosn
[1] = pLight
->Position
.y
;
2585 object
->lightPosn
[2] = pLight
->Position
.z
;
2586 object
->lightPosn
[3] = 1.0f
;
2589 object
->lightDirn
[0] = pLight
->Direction
.x
;
2590 object
->lightDirn
[1] = pLight
->Direction
.y
;
2591 object
->lightDirn
[2] = pLight
->Direction
.z
;
2592 object
->lightDirn
[3] = 1.0f
;
2595 * opengl-ish and d3d-ish spot lights use too different models for the
2596 * light "intensity" as a function of the angle towards the main light direction,
2597 * so we only can approximate very roughly.
2598 * however spot lights are rather rarely used in games (if ever used at all).
2599 * furthermore if still used, probably nobody pays attention to such details.
2601 if (pLight
->Falloff
== 0) {
2602 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2603 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2604 * will always be 1.0 for both of them, and we don't have to care for the
2605 * rest of the rather complex calculation
2607 object
->exponent
= 0.0f
;
2609 rho
= pLight
->Theta
+ (pLight
->Phi
- pLight
->Theta
)/(2*pLight
->Falloff
);
2610 if (rho
< 0.0001f
) rho
= 0.0001f
;
2611 object
->exponent
= -0.3f
/logf(cosf(rho
/2));
2613 if (object
->exponent
> 128.0f
)
2615 object
->exponent
= 128.0f
;
2617 object
->cutoff
= pLight
->Phi
*90/M_PI
;
2623 FIXME("Unrecognized light type %d\n", pLight
->Type
);
2626 /* Update the live definitions if the light is currently assigned a glIndex */
2627 if (object
->glIndex
!= -1 && !This
->isRecordingState
) {
2628 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(object
->glIndex
));
2633 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLight(IWineD3DDevice
*iface
, DWORD Index
, WINED3DLIGHT
*pLight
)
2635 struct wined3d_light_info
*lightInfo
= NULL
;
2636 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2637 DWORD Hi
= LIGHTMAP_HASHFUNC(Index
);
2639 TRACE("(%p) : Idx(%d), pLight(%p)\n", This
, Index
, pLight
);
2641 LIST_FOR_EACH(e
, &This
->stateBlock
->lightMap
[Hi
])
2643 lightInfo
= LIST_ENTRY(e
, struct wined3d_light_info
, entry
);
2644 if(lightInfo
->OriginalIndex
== Index
) break;
2648 if (lightInfo
== NULL
) {
2649 TRACE("Light information requested but light not defined\n");
2650 return WINED3DERR_INVALIDCALL
;
2653 *pLight
= lightInfo
->OriginalParms
;
2658 * Get / Set Light Enable
2659 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2661 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice
*iface
, DWORD Index
, BOOL Enable
)
2663 struct wined3d_light_info
*lightInfo
= NULL
;
2664 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2665 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2667 TRACE("(%p) : Idx(%d), enable? %d\n", This
, Index
, Enable
);
2669 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
])
2671 lightInfo
= LIST_ENTRY(e
, struct wined3d_light_info
, entry
);
2672 if(lightInfo
->OriginalIndex
== Index
) break;
2675 TRACE("Found light: %p\n", lightInfo
);
2677 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2678 if (lightInfo
== NULL
) {
2680 TRACE("Light enabled requested but light not defined, so defining one!\n");
2681 IWineD3DDeviceImpl_SetLight(iface
, Index
, &WINED3D_default_light
);
2683 /* Search for it again! Should be fairly quick as near head of list */
2684 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
])
2686 lightInfo
= LIST_ENTRY(e
, struct wined3d_light_info
, entry
);
2687 if(lightInfo
->OriginalIndex
== Index
) break;
2690 if (lightInfo
== NULL
) {
2691 FIXME("Adding default lights has failed dismally\n");
2692 return WINED3DERR_INVALIDCALL
;
2697 if(lightInfo
->glIndex
!= -1) {
2698 if(!This
->isRecordingState
) {
2699 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(lightInfo
->glIndex
));
2702 This
->updateStateBlock
->activeLights
[lightInfo
->glIndex
] = NULL
;
2703 lightInfo
->glIndex
= -1;
2705 TRACE("Light already disabled, nothing to do\n");
2707 lightInfo
->enabled
= FALSE
;
2709 lightInfo
->enabled
= TRUE
;
2710 if (lightInfo
->glIndex
!= -1) {
2712 TRACE("Nothing to do as light was enabled\n");
2715 /* Find a free gl light */
2716 for(i
= 0; i
< This
->maxConcurrentLights
; i
++) {
2717 if(This
->updateStateBlock
->activeLights
[i
] == NULL
) {
2718 This
->updateStateBlock
->activeLights
[i
] = lightInfo
;
2719 lightInfo
->glIndex
= i
;
2723 if(lightInfo
->glIndex
== -1) {
2724 /* Our tests show that Windows returns D3D_OK in this situation, even with
2725 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2726 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2727 * as well for those lights.
2729 * TODO: Test how this affects rendering
2731 WARN("Too many concurrently active lights\n");
2735 /* i == lightInfo->glIndex */
2736 if(!This
->isRecordingState
) {
2737 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(i
));
2745 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice
*iface
, DWORD Index
,BOOL
* pEnable
)
2747 struct wined3d_light_info
*lightInfo
= NULL
;
2748 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2750 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2751 TRACE("(%p) : for idx(%d)\n", This
, Index
);
2753 LIST_FOR_EACH(e
, &This
->stateBlock
->lightMap
[Hi
])
2755 lightInfo
= LIST_ENTRY(e
, struct wined3d_light_info
, entry
);
2756 if(lightInfo
->OriginalIndex
== Index
) break;
2760 if (lightInfo
== NULL
) {
2761 TRACE("Light enabled state requested but light not defined\n");
2762 return WINED3DERR_INVALIDCALL
;
2764 /* true is 128 according to SetLightEnable */
2765 *pEnable
= lightInfo
->enabled
? 128 : 0;
2770 * Get / Set Clip Planes
2772 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, CONST
float *pPlane
) {
2773 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2774 TRACE("(%p) : for idx %d, %p\n", This
, Index
, pPlane
);
2776 /* Validate Index */
2777 if (Index
>= This
->adapter
->gl_info
.limits
.clipplanes
)
2779 TRACE("Application has requested clipplane this device doesn't support\n");
2780 return WINED3DERR_INVALIDCALL
;
2783 This
->updateStateBlock
->changed
.clipplane
|= 1 << Index
;
2785 if(This
->updateStateBlock
->clipplane
[Index
][0] == pPlane
[0] &&
2786 This
->updateStateBlock
->clipplane
[Index
][1] == pPlane
[1] &&
2787 This
->updateStateBlock
->clipplane
[Index
][2] == pPlane
[2] &&
2788 This
->updateStateBlock
->clipplane
[Index
][3] == pPlane
[3]) {
2789 TRACE("Application is setting old values over, nothing to do\n");
2793 This
->updateStateBlock
->clipplane
[Index
][0] = pPlane
[0];
2794 This
->updateStateBlock
->clipplane
[Index
][1] = pPlane
[1];
2795 This
->updateStateBlock
->clipplane
[Index
][2] = pPlane
[2];
2796 This
->updateStateBlock
->clipplane
[Index
][3] = pPlane
[3];
2798 /* Handle recording of state blocks */
2799 if (This
->isRecordingState
) {
2800 TRACE("Recording... not performing anything\n");
2804 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_CLIPPLANE(Index
));
2809 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, float *pPlane
) {
2810 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2811 TRACE("(%p) : for idx %d\n", This
, Index
);
2813 /* Validate Index */
2814 if (Index
>= This
->adapter
->gl_info
.limits
.clipplanes
)
2816 TRACE("Application has requested clipplane this device doesn't support\n");
2817 return WINED3DERR_INVALIDCALL
;
2820 pPlane
[0] = This
->stateBlock
->clipplane
[Index
][0];
2821 pPlane
[1] = This
->stateBlock
->clipplane
[Index
][1];
2822 pPlane
[2] = This
->stateBlock
->clipplane
[Index
][2];
2823 pPlane
[3] = This
->stateBlock
->clipplane
[Index
][3];
2828 * Get / Set Clip Plane Status
2829 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2831 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice
*iface
, CONST WINED3DCLIPSTATUS
* pClipStatus
) {
2832 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2833 FIXME("(%p) : stub\n", This
);
2834 if (NULL
== pClipStatus
) {
2835 return WINED3DERR_INVALIDCALL
;
2837 This
->updateStateBlock
->clip_status
.ClipUnion
= pClipStatus
->ClipUnion
;
2838 This
->updateStateBlock
->clip_status
.ClipIntersection
= pClipStatus
->ClipIntersection
;
2842 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice
*iface
, WINED3DCLIPSTATUS
* pClipStatus
) {
2843 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2844 FIXME("(%p) : stub\n", This
);
2845 if (NULL
== pClipStatus
) {
2846 return WINED3DERR_INVALIDCALL
;
2848 pClipStatus
->ClipUnion
= This
->updateStateBlock
->clip_status
.ClipUnion
;
2849 pClipStatus
->ClipIntersection
= This
->updateStateBlock
->clip_status
.ClipIntersection
;
2854 * Get / Set Material
2856 static HRESULT WINAPI
IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice
*iface
, CONST WINED3DMATERIAL
* pMaterial
) {
2857 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2859 This
->updateStateBlock
->changed
.material
= TRUE
;
2860 This
->updateStateBlock
->material
= *pMaterial
;
2862 /* Handle recording of state blocks */
2863 if (This
->isRecordingState
) {
2864 TRACE("Recording... not performing anything\n");
2868 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_MATERIAL
);
2872 static HRESULT WINAPI
IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice
*iface
, WINED3DMATERIAL
* pMaterial
) {
2873 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2874 *pMaterial
= This
->updateStateBlock
->material
;
2875 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This
, pMaterial
->Diffuse
.r
, pMaterial
->Diffuse
.g
,
2876 pMaterial
->Diffuse
.b
, pMaterial
->Diffuse
.a
);
2877 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This
, pMaterial
->Ambient
.r
, pMaterial
->Ambient
.g
,
2878 pMaterial
->Ambient
.b
, pMaterial
->Ambient
.a
);
2879 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This
, pMaterial
->Specular
.r
, pMaterial
->Specular
.g
,
2880 pMaterial
->Specular
.b
, pMaterial
->Specular
.a
);
2881 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This
, pMaterial
->Emissive
.r
, pMaterial
->Emissive
.g
,
2882 pMaterial
->Emissive
.b
, pMaterial
->Emissive
.a
);
2883 TRACE("(%p) : Power (%f)\n", This
, pMaterial
->Power
);
2891 static HRESULT WINAPI
IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice
*iface
,
2892 IWineD3DBuffer
*pIndexData
, WINED3DFORMAT fmt
)
2894 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2895 IWineD3DBuffer
*oldIdxs
;
2897 TRACE("(%p) : Setting to %p\n", This
, pIndexData
);
2898 oldIdxs
= This
->updateStateBlock
->pIndexData
;
2900 This
->updateStateBlock
->changed
.indices
= TRUE
;
2901 This
->updateStateBlock
->pIndexData
= pIndexData
;
2902 This
->updateStateBlock
->IndexFmt
= fmt
;
2904 /* Handle recording of state blocks */
2905 if (This
->isRecordingState
) {
2906 TRACE("Recording... not performing anything\n");
2907 if(pIndexData
) IWineD3DBuffer_AddRef(pIndexData
);
2908 if(oldIdxs
) IWineD3DBuffer_Release(oldIdxs
);
2912 if(oldIdxs
!= pIndexData
) {
2913 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
2915 InterlockedIncrement(&((struct wined3d_buffer
*)pIndexData
)->bind_count
);
2916 IWineD3DBuffer_AddRef(pIndexData
);
2919 InterlockedDecrement(&((struct wined3d_buffer
*)oldIdxs
)->bind_count
);
2920 IWineD3DBuffer_Release(oldIdxs
);
2927 static HRESULT WINAPI
IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice
*iface
, IWineD3DBuffer
**ppIndexData
)
2929 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2931 *ppIndexData
= This
->stateBlock
->pIndexData
;
2933 /* up ref count on ppindexdata */
2935 IWineD3DBuffer_AddRef(*ppIndexData
);
2936 TRACE("(%p) index data set to %p\n", This
, ppIndexData
);
2938 TRACE("(%p) No index data set\n", This
);
2940 TRACE("Returning %p\n", *ppIndexData
);
2945 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2946 static HRESULT WINAPI
IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice
*iface
, INT BaseIndex
) {
2947 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2948 TRACE("(%p)->(%d)\n", This
, BaseIndex
);
2950 if(This
->updateStateBlock
->baseVertexIndex
== BaseIndex
) {
2951 TRACE("Application is setting the old value over, nothing to do\n");
2955 This
->updateStateBlock
->baseVertexIndex
= BaseIndex
;
2957 if (This
->isRecordingState
) {
2958 TRACE("Recording... not performing anything\n");
2961 /* The base vertex index affects the stream sources */
2962 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2966 static HRESULT WINAPI
IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice
*iface
, INT
* base_index
) {
2967 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2968 TRACE("(%p) : base_index %p\n", This
, base_index
);
2970 *base_index
= This
->stateBlock
->baseVertexIndex
;
2972 TRACE("Returning %u\n", *base_index
);
2978 * Get / Set Viewports
2980 static HRESULT WINAPI
IWineD3DDeviceImpl_SetViewport(IWineD3DDevice
*iface
, CONST WINED3DVIEWPORT
* pViewport
) {
2981 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2983 TRACE("(%p)\n", This
);
2984 This
->updateStateBlock
->changed
.viewport
= TRUE
;
2985 This
->updateStateBlock
->viewport
= *pViewport
;
2987 /* Handle recording of state blocks */
2988 if (This
->isRecordingState
) {
2989 TRACE("Recording... not performing anything\n");
2993 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This
,
2994 pViewport
->X
, pViewport
->Y
, pViewport
->Width
, pViewport
->Height
, pViewport
->MinZ
, pViewport
->MaxZ
);
2996 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VIEWPORT
);
3001 static HRESULT WINAPI
IWineD3DDeviceImpl_GetViewport(IWineD3DDevice
*iface
, WINED3DVIEWPORT
* pViewport
) {
3002 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3003 TRACE("(%p)\n", This
);
3004 *pViewport
= This
->stateBlock
->viewport
;
3009 * Get / Set Render States
3010 * TODO: Verify against dx9 definitions
3012 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice
*iface
, WINED3DRENDERSTATETYPE State
, DWORD Value
) {
3014 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3015 DWORD oldValue
= This
->stateBlock
->renderState
[State
];
3017 TRACE("(%p)->state = %s(%d), value = %d\n", This
, debug_d3drenderstate(State
), State
, Value
);
3019 This
->updateStateBlock
->changed
.renderState
[State
>> 5] |= 1 << (State
& 0x1f);
3020 This
->updateStateBlock
->renderState
[State
] = Value
;
3022 /* Handle recording of state blocks */
3023 if (This
->isRecordingState
) {
3024 TRACE("Recording... not performing anything\n");
3028 /* Compared here and not before the assignment to allow proper stateblock recording */
3029 if(Value
== oldValue
) {
3030 TRACE("Application is setting the old value over, nothing to do\n");
3032 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(State
));
3038 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice
*iface
, WINED3DRENDERSTATETYPE State
, DWORD
*pValue
) {
3039 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3040 TRACE("(%p) for State %d = %d\n", This
, State
, This
->stateBlock
->renderState
[State
]);
3041 *pValue
= This
->stateBlock
->renderState
[State
];
3046 * Get / Set Sampler States
3047 * TODO: Verify against dx9 definitions
3050 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD Value
) {
3051 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3054 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3055 This
, Sampler
, debug_d3dsamplerstate(Type
), Type
, Value
);
3057 if (Sampler
>= WINED3DVERTEXTEXTURESAMPLER0
&& Sampler
<= WINED3DVERTEXTEXTURESAMPLER3
) {
3058 Sampler
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
3061 if (Sampler
>= sizeof(This
->stateBlock
->samplerState
)/sizeof(This
->stateBlock
->samplerState
[0])) {
3062 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler
);
3063 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
3066 * SetSampler is designed to allow for more than the standard up to 8 textures
3067 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3068 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3070 * http://developer.nvidia.com/object/General_FAQ.html#t6
3072 * There are two new settings for GForce
3074 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3075 * and the texture one:
3076 * GL_MAX_TEXTURE_COORDS_ARB.
3077 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3080 oldValue
= This
->stateBlock
->samplerState
[Sampler
][Type
];
3081 This
->updateStateBlock
->samplerState
[Sampler
][Type
] = Value
;
3082 This
->updateStateBlock
->changed
.samplerState
[Sampler
] |= 1 << Type
;
3084 /* Handle recording of state blocks */
3085 if (This
->isRecordingState
) {
3086 TRACE("Recording... not performing anything\n");
3090 if(oldValue
== Value
) {
3091 TRACE("Application is setting the old value over, nothing to do\n");
3095 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(Sampler
));
3100 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD
* Value
) {
3101 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3103 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3104 This
, Sampler
, debug_d3dsamplerstate(Type
), Type
);
3106 if (Sampler
>= WINED3DVERTEXTEXTURESAMPLER0
&& Sampler
<= WINED3DVERTEXTEXTURESAMPLER3
) {
3107 Sampler
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
3110 if (Sampler
>= sizeof(This
->stateBlock
->samplerState
)/sizeof(This
->stateBlock
->samplerState
[0])) {
3111 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler
);
3112 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
3114 *Value
= This
->stateBlock
->samplerState
[Sampler
][Type
];
3115 TRACE("(%p) : Returning %#x\n", This
, *Value
);
3120 static HRESULT WINAPI
IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice
*iface
, CONST RECT
* pRect
) {
3121 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3123 This
->updateStateBlock
->changed
.scissorRect
= TRUE
;
3124 if(EqualRect(&This
->updateStateBlock
->scissorRect
, pRect
)) {
3125 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3128 CopyRect(&This
->updateStateBlock
->scissorRect
, pRect
);
3130 if(This
->isRecordingState
) {
3131 TRACE("Recording... not performing anything\n");
3135 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SCISSORRECT
);
3140 static HRESULT WINAPI
IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice
*iface
, RECT
* pRect
) {
3141 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3143 *pRect
= This
->updateStateBlock
->scissorRect
;
3144 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This
, pRect
->left
, pRect
->top
, pRect
->right
, pRect
->bottom
);
3148 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
* pDecl
) {
3149 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
3150 IWineD3DVertexDeclaration
*oldDecl
= This
->updateStateBlock
->vertexDecl
;
3152 TRACE("(%p) : pDecl=%p\n", This
, pDecl
);
3154 if (pDecl
) IWineD3DVertexDeclaration_AddRef(pDecl
);
3155 if (oldDecl
) IWineD3DVertexDeclaration_Release(oldDecl
);
3157 This
->updateStateBlock
->vertexDecl
= pDecl
;
3158 This
->updateStateBlock
->changed
.vertexDecl
= TRUE
;
3160 if (This
->isRecordingState
) {
3161 TRACE("Recording... not performing anything\n");
3163 } else if(pDecl
== oldDecl
) {
3164 /* Checked after the assignment to allow proper stateblock recording */
3165 TRACE("Application is setting the old declaration over, nothing to do\n");
3169 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
3173 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppDecl
) {
3174 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3176 TRACE("(%p) : ppDecl=%p\n", This
, ppDecl
);
3178 *ppDecl
= This
->stateBlock
->vertexDecl
;
3179 if (NULL
!= *ppDecl
) IWineD3DVertexDeclaration_AddRef(*ppDecl
);
3183 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
* pShader
) {
3184 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3185 IWineD3DVertexShader
* oldShader
= This
->updateStateBlock
->vertexShader
;
3187 This
->updateStateBlock
->vertexShader
= pShader
;
3188 This
->updateStateBlock
->changed
.vertexShader
= TRUE
;
3190 if (This
->isRecordingState
) {
3191 if(pShader
) IWineD3DVertexShader_AddRef(pShader
);
3192 if(oldShader
) IWineD3DVertexShader_Release(oldShader
);
3193 TRACE("Recording... not performing anything\n");
3195 } else if(oldShader
== pShader
) {
3196 /* Checked here to allow proper stateblock recording */
3197 TRACE("App is setting the old shader over, nothing to do\n");
3201 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
3202 if(pShader
) IWineD3DVertexShader_AddRef(pShader
);
3203 if(oldShader
) IWineD3DVertexShader_Release(oldShader
);
3205 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VSHADER
);
3210 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
** ppShader
) {
3211 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3213 if (NULL
== ppShader
) {
3214 return WINED3DERR_INVALIDCALL
;
3216 *ppShader
= This
->stateBlock
->vertexShader
;
3217 if( NULL
!= *ppShader
)
3218 IWineD3DVertexShader_AddRef(*ppShader
);
3220 TRACE("(%p) : returning %p\n", This
, *ppShader
);
3224 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantB(
3225 IWineD3DDevice
*iface
,
3227 CONST BOOL
*srcData
,
3230 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3231 unsigned int i
, cnt
= min(count
, MAX_CONST_B
- start
);
3233 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3234 iface
, srcData
, start
, count
);
3236 if (!srcData
|| start
>= MAX_CONST_B
) return WINED3DERR_INVALIDCALL
;
3238 memcpy(&This
->updateStateBlock
->vertexShaderConstantB
[start
], srcData
, cnt
* sizeof(BOOL
));
3239 for (i
= 0; i
< cnt
; i
++)
3240 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
3242 for (i
= start
; i
< cnt
+ start
; ++i
) {
3243 This
->updateStateBlock
->changed
.vertexShaderConstantsB
|= (1 << i
);
3246 if (!This
->isRecordingState
) IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3251 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantB(
3252 IWineD3DDevice
*iface
,
3257 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3258 int cnt
= min(count
, MAX_CONST_B
- start
);
3260 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3261 iface
, dstData
, start
, count
);
3263 if (dstData
== NULL
|| cnt
< 0)
3264 return WINED3DERR_INVALIDCALL
;
3266 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantB
[start
], cnt
* sizeof(BOOL
));
3270 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantI(
3271 IWineD3DDevice
*iface
,
3276 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3277 unsigned int i
, cnt
= min(count
, MAX_CONST_I
- start
);
3279 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3280 iface
, srcData
, start
, count
);
3282 if (!srcData
|| start
>= MAX_CONST_I
) return WINED3DERR_INVALIDCALL
;
3284 memcpy(&This
->updateStateBlock
->vertexShaderConstantI
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
3285 for (i
= 0; i
< cnt
; i
++)
3286 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
3287 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3289 for (i
= start
; i
< cnt
+ start
; ++i
) {
3290 This
->updateStateBlock
->changed
.vertexShaderConstantsI
|= (1 << i
);
3293 if (!This
->isRecordingState
) IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3298 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantI(
3299 IWineD3DDevice
*iface
,
3304 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3305 int cnt
= min(count
, MAX_CONST_I
- start
);
3307 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3308 iface
, dstData
, start
, count
);
3310 if (dstData
== NULL
|| ((signed int) MAX_CONST_I
- (signed int) start
) <= (signed int) 0)
3311 return WINED3DERR_INVALIDCALL
;
3313 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantI
[start
* 4], cnt
* sizeof(int) * 4);
3317 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantF(
3318 IWineD3DDevice
*iface
,
3320 CONST
float *srcData
,
3323 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3326 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3327 iface
, srcData
, start
, count
);
3329 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3330 if (srcData
== NULL
|| start
+ count
> This
->d3d_vshader_constantF
|| start
> This
->d3d_vshader_constantF
)
3331 return WINED3DERR_INVALIDCALL
;
3333 memcpy(&This
->updateStateBlock
->vertexShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
3335 for (i
= 0; i
< count
; i
++)
3336 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
3337 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3340 if (!This
->isRecordingState
)
3342 This
->shader_backend
->shader_update_float_vertex_constants(iface
, start
, count
);
3343 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3346 memset(This
->updateStateBlock
->changed
.vertexShaderConstantsF
+ start
, 1,
3347 sizeof(*This
->updateStateBlock
->changed
.vertexShaderConstantsF
) * count
);
3352 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantF(
3353 IWineD3DDevice
*iface
,
3358 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3359 int cnt
= min(count
, This
->d3d_vshader_constantF
- start
);
3361 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3362 iface
, dstData
, start
, count
);
3364 if (dstData
== NULL
|| cnt
< 0)
3365 return WINED3DERR_INVALIDCALL
;
3367 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantF
[start
* 4], cnt
* sizeof(float) * 4);
3371 static inline void markTextureStagesDirty(IWineD3DDeviceImpl
*This
, DWORD stage
) {
3373 for(i
= 0; i
<= WINED3D_HIGHEST_TEXTURE_STATE
; ++i
)
3375 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, i
));
3379 static void device_map_stage(IWineD3DDeviceImpl
*This
, DWORD stage
, DWORD unit
)
3381 DWORD i
= This
->rev_tex_unit_map
[unit
];
3382 DWORD j
= This
->texUnitMap
[stage
];
3384 This
->texUnitMap
[stage
] = unit
;
3385 if (i
!= WINED3D_UNMAPPED_STAGE
&& i
!= stage
)
3387 This
->texUnitMap
[i
] = WINED3D_UNMAPPED_STAGE
;
3390 This
->rev_tex_unit_map
[unit
] = stage
;
3391 if (j
!= WINED3D_UNMAPPED_STAGE
&& j
!= unit
)
3393 This
->rev_tex_unit_map
[j
] = WINED3D_UNMAPPED_STAGE
;
3397 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl
*This
) {
3400 This
->fixed_function_usage_map
= 0;
3401 for (i
= 0; i
< MAX_TEXTURES
; ++i
) {
3402 WINED3DTEXTUREOP color_op
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLOROP
];
3403 WINED3DTEXTUREOP alpha_op
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAOP
];
3404 DWORD color_arg1
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG1
] & WINED3DTA_SELECTMASK
;
3405 DWORD color_arg2
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG2
] & WINED3DTA_SELECTMASK
;
3406 DWORD color_arg3
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG0
] & WINED3DTA_SELECTMASK
;
3407 DWORD alpha_arg1
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG1
] & WINED3DTA_SELECTMASK
;
3408 DWORD alpha_arg2
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG2
] & WINED3DTA_SELECTMASK
;
3409 DWORD alpha_arg3
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG0
] & WINED3DTA_SELECTMASK
;
3411 if (color_op
== WINED3DTOP_DISABLE
) {
3412 /* Not used, and disable higher stages */
3416 if (((color_arg1
== WINED3DTA_TEXTURE
) && color_op
!= WINED3DTOP_SELECTARG2
)
3417 || ((color_arg2
== WINED3DTA_TEXTURE
) && color_op
!= WINED3DTOP_SELECTARG1
)
3418 || ((color_arg3
== WINED3DTA_TEXTURE
) && (color_op
== WINED3DTOP_MULTIPLYADD
|| color_op
== WINED3DTOP_LERP
))
3419 || ((alpha_arg1
== WINED3DTA_TEXTURE
) && alpha_op
!= WINED3DTOP_SELECTARG2
)
3420 || ((alpha_arg2
== WINED3DTA_TEXTURE
) && alpha_op
!= WINED3DTOP_SELECTARG1
)
3421 || ((alpha_arg3
== WINED3DTA_TEXTURE
) && (alpha_op
== WINED3DTOP_MULTIPLYADD
|| alpha_op
== WINED3DTOP_LERP
))) {
3422 This
->fixed_function_usage_map
|= (1 << i
);
3425 if ((color_op
== WINED3DTOP_BUMPENVMAP
|| color_op
== WINED3DTOP_BUMPENVMAPLUMINANCE
) && i
< MAX_TEXTURES
- 1) {
3426 This
->fixed_function_usage_map
|= (1 << (i
+ 1));
3431 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl
*This
) {
3432 unsigned int i
, tex
;
3435 device_update_fixed_function_usage_map(This
);
3436 ffu_map
= This
->fixed_function_usage_map
;
3438 if (This
->max_ffp_textures
== This
->max_ffp_texture_stages
||
3439 This
->stateBlock
->lowest_disabled_stage
<= This
->max_ffp_textures
) {
3440 for (i
= 0; ffu_map
; ffu_map
>>= 1, ++i
)
3442 if (!(ffu_map
& 1)) continue;
3444 if (This
->texUnitMap
[i
] != i
) {
3445 device_map_stage(This
, i
, i
);
3446 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3447 markTextureStagesDirty(This
, i
);
3453 /* Now work out the mapping */
3455 for (i
= 0; ffu_map
; ffu_map
>>= 1, ++i
)
3457 if (!(ffu_map
& 1)) continue;
3459 if (This
->texUnitMap
[i
] != tex
) {
3460 device_map_stage(This
, i
, tex
);
3461 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3462 markTextureStagesDirty(This
, i
);
3469 static void device_map_psamplers(IWineD3DDeviceImpl
*This
) {
3470 const WINED3DSAMPLER_TEXTURE_TYPE
*sampler_type
=
3471 ((IWineD3DPixelShaderImpl
*)This
->stateBlock
->pixelShader
)->baseShader
.reg_maps
.sampler_type
;
3474 for (i
= 0; i
< MAX_FRAGMENT_SAMPLERS
; ++i
) {
3475 if (sampler_type
[i
] && This
->texUnitMap
[i
] != i
)
3477 device_map_stage(This
, i
, i
);
3478 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3479 if (i
< MAX_TEXTURES
) {
3480 markTextureStagesDirty(This
, i
);
3486 static BOOL
device_unit_free_for_vs(IWineD3DDeviceImpl
*This
, const DWORD
*pshader_sampler_tokens
,
3487 const DWORD
*vshader_sampler_tokens
, DWORD unit
)
3489 DWORD current_mapping
= This
->rev_tex_unit_map
[unit
];
3491 /* Not currently used */
3492 if (current_mapping
== WINED3D_UNMAPPED_STAGE
) return TRUE
;
3494 if (current_mapping
< MAX_FRAGMENT_SAMPLERS
) {
3495 /* Used by a fragment sampler */
3497 if (!pshader_sampler_tokens
) {
3498 /* No pixel shader, check fixed function */
3499 return current_mapping
>= MAX_TEXTURES
|| !(This
->fixed_function_usage_map
& (1 << current_mapping
));
3502 /* Pixel shader, check the shader's sampler map */
3503 return !pshader_sampler_tokens
[current_mapping
];
3506 /* Used by a vertex sampler */
3507 return !vshader_sampler_tokens
[current_mapping
- MAX_FRAGMENT_SAMPLERS
];
3510 static void device_map_vsamplers(IWineD3DDeviceImpl
*This
, BOOL ps
) {
3511 const WINED3DSAMPLER_TEXTURE_TYPE
*vshader_sampler_type
=
3512 ((IWineD3DVertexShaderImpl
*)This
->stateBlock
->vertexShader
)->baseShader
.reg_maps
.sampler_type
;
3513 const WINED3DSAMPLER_TEXTURE_TYPE
*pshader_sampler_type
= NULL
;
3514 int start
= min(MAX_COMBINED_SAMPLERS
, This
->adapter
->gl_info
.limits
.combined_samplers
) - 1;
3518 IWineD3DPixelShaderImpl
*pshader
= (IWineD3DPixelShaderImpl
*)This
->stateBlock
->pixelShader
;
3520 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3521 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3522 pshader_sampler_type
= pshader
->baseShader
.reg_maps
.sampler_type
;
3525 for (i
= 0; i
< MAX_VERTEX_SAMPLERS
; ++i
) {
3526 DWORD vsampler_idx
= i
+ MAX_FRAGMENT_SAMPLERS
;
3527 if (vshader_sampler_type
[i
])
3529 if (This
->texUnitMap
[vsampler_idx
] != WINED3D_UNMAPPED_STAGE
)
3531 /* Already mapped somewhere */
3535 while (start
>= 0) {
3536 if (device_unit_free_for_vs(This
, pshader_sampler_type
, vshader_sampler_type
, start
))
3538 device_map_stage(This
, vsampler_idx
, start
);
3539 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(vsampler_idx
));
3551 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl
*This
) {
3552 BOOL vs
= use_vs(This
->stateBlock
);
3553 BOOL ps
= use_ps(This
->stateBlock
);
3556 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3557 * that would be really messy and require shader recompilation
3558 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3559 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3562 device_map_psamplers(This
);
3564 device_map_fixed_function_samplers(This
);
3568 device_map_vsamplers(This
, ps
);
3572 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
*pShader
) {
3573 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3574 IWineD3DPixelShader
*oldShader
= This
->updateStateBlock
->pixelShader
;
3575 This
->updateStateBlock
->pixelShader
= pShader
;
3576 This
->updateStateBlock
->changed
.pixelShader
= TRUE
;
3578 /* Handle recording of state blocks */
3579 if (This
->isRecordingState
) {
3580 TRACE("Recording... not performing anything\n");
3583 if (This
->isRecordingState
) {
3584 TRACE("Recording... not performing anything\n");
3585 if(pShader
) IWineD3DPixelShader_AddRef(pShader
);
3586 if(oldShader
) IWineD3DPixelShader_Release(oldShader
);
3590 if(pShader
== oldShader
) {
3591 TRACE("App is setting the old pixel shader over, nothing to do\n");
3595 if(pShader
) IWineD3DPixelShader_AddRef(pShader
);
3596 if(oldShader
) IWineD3DPixelShader_Release(oldShader
);
3598 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
3599 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADER
);
3604 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
**ppShader
) {
3605 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3607 if (NULL
== ppShader
) {
3608 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This
);
3609 return WINED3DERR_INVALIDCALL
;
3612 *ppShader
= This
->stateBlock
->pixelShader
;
3613 if (NULL
!= *ppShader
) {
3614 IWineD3DPixelShader_AddRef(*ppShader
);
3616 TRACE("(%p) : returning %p\n", This
, *ppShader
);
3620 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantB(
3621 IWineD3DDevice
*iface
,
3623 CONST BOOL
*srcData
,
3626 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3627 unsigned int i
, cnt
= min(count
, MAX_CONST_B
- start
);
3629 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3630 iface
, srcData
, start
, count
);
3632 if (!srcData
|| start
>= MAX_CONST_B
) return WINED3DERR_INVALIDCALL
;
3634 memcpy(&This
->updateStateBlock
->pixelShaderConstantB
[start
], srcData
, cnt
* sizeof(BOOL
));
3635 for (i
= 0; i
< cnt
; i
++)
3636 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
3638 for (i
= start
; i
< cnt
+ start
; ++i
) {
3639 This
->updateStateBlock
->changed
.pixelShaderConstantsB
|= (1 << i
);
3642 if (!This
->isRecordingState
) IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3647 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantB(
3648 IWineD3DDevice
*iface
,
3653 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3654 int cnt
= min(count
, MAX_CONST_B
- start
);
3656 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3657 iface
, dstData
, start
, count
);
3659 if (dstData
== NULL
|| cnt
< 0)
3660 return WINED3DERR_INVALIDCALL
;
3662 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantB
[start
], cnt
* sizeof(BOOL
));
3666 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantI(
3667 IWineD3DDevice
*iface
,
3672 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3673 unsigned int i
, cnt
= min(count
, MAX_CONST_I
- start
);
3675 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3676 iface
, srcData
, start
, count
);
3678 if (!srcData
|| start
>= MAX_CONST_I
) return WINED3DERR_INVALIDCALL
;
3680 memcpy(&This
->updateStateBlock
->pixelShaderConstantI
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
3681 for (i
= 0; i
< cnt
; i
++)
3682 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
3683 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3685 for (i
= start
; i
< cnt
+ start
; ++i
) {
3686 This
->updateStateBlock
->changed
.pixelShaderConstantsI
|= (1 << i
);
3689 if (!This
->isRecordingState
) IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3694 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantI(
3695 IWineD3DDevice
*iface
,
3700 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3701 int cnt
= min(count
, MAX_CONST_I
- start
);
3703 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3704 iface
, dstData
, start
, count
);
3706 if (dstData
== NULL
|| cnt
< 0)
3707 return WINED3DERR_INVALIDCALL
;
3709 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantI
[start
* 4], cnt
* sizeof(int) * 4);
3713 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantF(
3714 IWineD3DDevice
*iface
,
3716 CONST
float *srcData
,
3719 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3722 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3723 iface
, srcData
, start
, count
);
3725 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3726 if (srcData
== NULL
|| start
+ count
> This
->d3d_pshader_constantF
|| start
> This
->d3d_pshader_constantF
)
3727 return WINED3DERR_INVALIDCALL
;
3729 memcpy(&This
->updateStateBlock
->pixelShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
3731 for (i
= 0; i
< count
; i
++)
3732 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
3733 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3736 if (!This
->isRecordingState
)
3738 This
->shader_backend
->shader_update_float_pixel_constants(iface
, start
, count
);
3739 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3742 memset(This
->updateStateBlock
->changed
.pixelShaderConstantsF
+ start
, 1,
3743 sizeof(*This
->updateStateBlock
->changed
.pixelShaderConstantsF
) * count
);
3748 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantF(
3749 IWineD3DDevice
*iface
,
3754 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3755 int cnt
= min(count
, This
->d3d_pshader_constantF
- start
);
3757 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3758 iface
, dstData
, start
, count
);
3760 if (dstData
== NULL
|| cnt
< 0)
3761 return WINED3DERR_INVALIDCALL
;
3763 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantF
[start
* 4], cnt
* sizeof(float) * 4);
3767 /* Context activation is done by the caller. */
3768 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3769 static HRESULT
process_vertices_strided(IWineD3DDeviceImpl
*This
, DWORD dwDestIndex
, DWORD dwCount
,
3770 const struct wined3d_stream_info
*stream_info
, struct wined3d_buffer
*dest
, DWORD dwFlags
,
3773 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
3774 char *dest_ptr
, *dest_conv
= NULL
, *dest_conv_addr
= NULL
;
3777 WINED3DMATRIX mat
, proj_mat
, view_mat
, world_mat
;
3781 if (stream_info
->use_map
& (1 << WINED3D_FFP_NORMAL
))
3783 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3786 if (!(stream_info
->use_map
& (1 << WINED3D_FFP_POSITION
)))
3788 ERR("Source has no position mask\n");
3789 return WINED3DERR_INVALIDCALL
;
3792 /* We might access VBOs from this code, so hold the lock */
3795 if (dest
->resource
.allocatedMemory
== NULL
) {
3796 buffer_get_sysmem(dest
);
3799 /* Get a pointer into the destination vbo(create one if none exists) and
3800 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3802 if (!dest
->buffer_object
&& gl_info
->supported
[ARB_VERTEX_BUFFER_OBJECT
])
3804 dest
->flags
|= WINED3D_BUFFER_CREATEBO
;
3805 IWineD3DBuffer_PreLoad((IWineD3DBuffer
*)dest
);
3808 if (dest
->buffer_object
)
3810 unsigned char extrabytes
= 0;
3811 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3812 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3813 * this may write 4 extra bytes beyond the area that should be written
3815 if(DestFVF
== WINED3DFVF_XYZ
) extrabytes
= 4;
3816 dest_conv_addr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwCount
* get_flexible_vertex_size(DestFVF
) + extrabytes
);
3817 if(!dest_conv_addr
) {
3818 ERR("Out of memory\n");
3819 /* Continue without storing converted vertices */
3821 dest_conv
= dest_conv_addr
;
3825 * a) WINED3DRS_CLIPPING is enabled
3826 * b) WINED3DVOP_CLIP is passed
3828 if(This
->stateBlock
->renderState
[WINED3DRS_CLIPPING
]) {
3829 static BOOL warned
= FALSE
;
3831 * The clipping code is not quite correct. Some things need
3832 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3833 * so disable clipping for now.
3834 * (The graphics in Half-Life are broken, and my processvertices
3835 * test crashes with IDirect3DDevice3)
3841 FIXME("Clipping is broken and disabled for now\n");
3843 } else doClip
= FALSE
;
3844 dest_ptr
= ((char *) buffer_get_sysmem(dest
)) + dwDestIndex
* get_flexible_vertex_size(DestFVF
);
3846 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
3849 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
3850 WINED3DTS_PROJECTION
,
3852 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
3853 WINED3DTS_WORLDMATRIX(0),
3856 TRACE("View mat:\n");
3857 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
);
3858 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
);
3859 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
);
3860 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
);
3862 TRACE("Proj mat:\n");
3863 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
);
3864 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
);
3865 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
);
3866 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
);
3868 TRACE("World mat:\n");
3869 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
);
3870 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
);
3871 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
);
3872 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
);
3874 /* Get the viewport */
3875 IWineD3DDevice_GetViewport( (IWineD3DDevice
*) This
, &vp
);
3876 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3877 vp
.X
, vp
.Y
, vp
.Width
, vp
.Height
, vp
.MinZ
, vp
.MaxZ
);
3879 multiply_matrix(&mat
,&view_mat
,&world_mat
);
3880 multiply_matrix(&mat
,&proj_mat
,&mat
);
3882 numTextures
= (DestFVF
& WINED3DFVF_TEXCOUNT_MASK
) >> WINED3DFVF_TEXCOUNT_SHIFT
;
3884 for (i
= 0; i
< dwCount
; i
+= 1) {
3885 unsigned int tex_index
;
3887 if ( ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZ
) ||
3888 ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) ) {
3889 /* The position first */
3890 const struct wined3d_stream_info_element
*element
= &stream_info
->elements
[WINED3D_FFP_POSITION
];
3891 const float *p
= (const float *)(element
->data
+ i
* element
->stride
);
3893 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p
[0], p
[1], p
[2]);
3895 /* Multiplication with world, view and projection matrix */
3896 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
);
3897 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
);
3898 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
);
3899 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
);
3901 TRACE("x=%f y=%f z=%f rhw=%f\n", x
, y
, z
, rhw
);
3903 /* WARNING: The following things are taken from d3d7 and were not yet checked
3904 * against d3d8 or d3d9!
3907 /* Clipping conditions: From msdn
3909 * A vertex is clipped if it does not match the following requirements
3913 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3915 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3916 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3921 ( (-rhw
-eps
< x
) && (-rhw
-eps
< y
) && ( -eps
< z
) &&
3922 (x
<= rhw
+ eps
) && (y
<= rhw
+ eps
) && (z
<= rhw
+ eps
) &&
3925 /* "Normal" viewport transformation (not clipped)
3926 * 1) The values are divided by rhw
3927 * 2) The y axis is negative, so multiply it with -1
3928 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3929 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3930 * 4) Multiply x with Width/2 and add Width/2
3931 * 5) The same for the height
3932 * 6) Add the viewpoint X and Y to the 2D coordinates and
3933 * The minimum Z value to z
3934 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3936 * Well, basically it's simply a linear transformation into viewport
3948 z
*= vp
.MaxZ
- vp
.MinZ
;
3950 x
+= vp
.Width
/ 2 + vp
.X
;
3951 y
+= vp
.Height
/ 2 + vp
.Y
;
3956 /* That vertex got clipped
3957 * Contrary to OpenGL it is not dropped completely, it just
3958 * undergoes a different calculation.
3960 TRACE("Vertex got clipped\n");
3967 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3968 * outside of the main vertex buffer memory. That needs some more
3973 TRACE("Writing (%f %f %f) %f\n", x
, y
, z
, rhw
);
3976 ( (float *) dest_ptr
)[0] = x
;
3977 ( (float *) dest_ptr
)[1] = y
;
3978 ( (float *) dest_ptr
)[2] = z
;
3979 ( (float *) dest_ptr
)[3] = rhw
; /* SIC, see ddraw test! */
3981 dest_ptr
+= 3 * sizeof(float);
3983 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
3984 dest_ptr
+= sizeof(float);
3989 ( (float *) dest_conv
)[0] = x
* w
;
3990 ( (float *) dest_conv
)[1] = y
* w
;
3991 ( (float *) dest_conv
)[2] = z
* w
;
3992 ( (float *) dest_conv
)[3] = w
;
3994 dest_conv
+= 3 * sizeof(float);
3996 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
3997 dest_conv
+= sizeof(float);
4001 if (DestFVF
& WINED3DFVF_PSIZE
) {
4002 dest_ptr
+= sizeof(DWORD
);
4003 if(dest_conv
) dest_conv
+= sizeof(DWORD
);
4005 if (DestFVF
& WINED3DFVF_NORMAL
) {
4006 const struct wined3d_stream_info_element
*element
= &stream_info
->elements
[WINED3D_FFP_NORMAL
];
4007 const float *normal
= (const float *)(element
->data
+ i
* element
->stride
);
4008 /* AFAIK this should go into the lighting information */
4009 FIXME("Didn't expect the destination to have a normal\n");
4010 copy_and_next(dest_ptr
, normal
, 3 * sizeof(float));
4012 copy_and_next(dest_conv
, normal
, 3 * sizeof(float));
4016 if (DestFVF
& WINED3DFVF_DIFFUSE
) {
4017 const struct wined3d_stream_info_element
*element
= &stream_info
->elements
[WINED3D_FFP_DIFFUSE
];
4018 const DWORD
*color_d
= (const DWORD
*)(element
->data
+ i
* element
->stride
);
4019 if (!(stream_info
->use_map
& (1 << WINED3D_FFP_DIFFUSE
)))
4021 static BOOL warned
= FALSE
;
4024 ERR("No diffuse color in source, but destination has one\n");
4028 *( (DWORD
*) dest_ptr
) = 0xffffffff;
4029 dest_ptr
+= sizeof(DWORD
);
4032 *( (DWORD
*) dest_conv
) = 0xffffffff;
4033 dest_conv
+= sizeof(DWORD
);
4037 copy_and_next(dest_ptr
, color_d
, sizeof(DWORD
));
4039 *( (DWORD
*) dest_conv
) = (*color_d
& 0xff00ff00) ; /* Alpha + green */
4040 *( (DWORD
*) dest_conv
) |= (*color_d
& 0x00ff0000) >> 16; /* Red */
4041 *( (DWORD
*) dest_conv
) |= (*color_d
& 0xff0000ff) << 16; /* Blue */
4042 dest_conv
+= sizeof(DWORD
);
4047 if (DestFVF
& WINED3DFVF_SPECULAR
)
4049 /* What's the color value in the feedback buffer? */
4050 const struct wined3d_stream_info_element
*element
= &stream_info
->elements
[WINED3D_FFP_SPECULAR
];
4051 const DWORD
*color_s
= (const DWORD
*)(element
->data
+ i
* element
->stride
);
4052 if (!(stream_info
->use_map
& (1 << WINED3D_FFP_SPECULAR
)))
4054 static BOOL warned
= FALSE
;
4057 ERR("No specular color in source, but destination has one\n");
4061 *( (DWORD
*) dest_ptr
) = 0xFF000000;
4062 dest_ptr
+= sizeof(DWORD
);
4065 *( (DWORD
*) dest_conv
) = 0xFF000000;
4066 dest_conv
+= sizeof(DWORD
);
4070 copy_and_next(dest_ptr
, color_s
, sizeof(DWORD
));
4072 *( (DWORD
*) dest_conv
) = (*color_s
& 0xff00ff00) ; /* Alpha + green */
4073 *( (DWORD
*) dest_conv
) |= (*color_s
& 0x00ff0000) >> 16; /* Red */
4074 *( (DWORD
*) dest_conv
) |= (*color_s
& 0xff0000ff) << 16; /* Blue */
4075 dest_conv
+= sizeof(DWORD
);
4080 for (tex_index
= 0; tex_index
< numTextures
; tex_index
++) {
4081 const struct wined3d_stream_info_element
*element
= &stream_info
->elements
[WINED3D_FFP_TEXCOORD0
+ tex_index
];
4082 const float *tex_coord
= (const float *)(element
->data
+ i
* element
->stride
);
4083 if (!(stream_info
->use_map
& (1 << (WINED3D_FFP_TEXCOORD0
+ tex_index
))))
4085 ERR("No source texture, but destination requests one\n");
4086 dest_ptr
+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
4087 if(dest_conv
) dest_conv
+= GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
4090 copy_and_next(dest_ptr
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
4092 copy_and_next(dest_conv
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
4099 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, dest
->buffer_object
));
4100 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4101 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB
, dwDestIndex
* get_flexible_vertex_size(DestFVF
),
4102 dwCount
* get_flexible_vertex_size(DestFVF
),
4104 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4105 HeapFree(GetProcessHeap(), 0, dest_conv_addr
);
4112 #undef copy_and_next
4114 static HRESULT WINAPI
IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice
*iface
, UINT SrcStartIndex
, UINT DestIndex
,
4115 UINT VertexCount
, IWineD3DBuffer
*pDestBuffer
, IWineD3DVertexDeclaration
*pVertexDecl
, DWORD Flags
,
4118 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4119 struct wined3d_stream_info stream_info
;
4120 struct wined3d_context
*context
;
4121 BOOL vbo
= FALSE
, streamWasUP
= This
->stateBlock
->streamIsUP
;
4124 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This
, SrcStartIndex
, DestIndex
, VertexCount
, pDestBuffer
, pVertexDecl
, Flags
);
4127 ERR("Output vertex declaration not implemented yet\n");
4130 /* Need any context to write to the vbo. */
4131 context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
4133 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4134 * control the streamIsUP flag, thus restore it afterwards.
4136 This
->stateBlock
->streamIsUP
= FALSE
;
4137 device_stream_info_from_declaration(This
, FALSE
, &stream_info
, &vbo
);
4138 This
->stateBlock
->streamIsUP
= streamWasUP
;
4140 if(vbo
|| SrcStartIndex
) {
4142 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4143 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4145 * Also get the start index in, but only loop over all elements if there's something to add at all.
4147 for (i
= 0; i
< (sizeof(stream_info
.elements
) / sizeof(*stream_info
.elements
)); ++i
)
4149 struct wined3d_stream_info_element
*e
;
4151 if (!(stream_info
.use_map
& (1 << i
))) continue;
4153 e
= &stream_info
.elements
[i
];
4154 if (e
->buffer_object
)
4156 struct wined3d_buffer
*vb
= (struct wined3d_buffer
*)This
->stateBlock
->streamSource
[e
->stream_idx
];
4157 e
->buffer_object
= 0;
4158 e
->data
= (BYTE
*)((unsigned long)e
->data
+ (unsigned long)buffer_get_sysmem(vb
));
4160 GL_EXTCALL(glDeleteBuffersARB(1, &vb
->buffer_object
));
4161 vb
->buffer_object
= 0;
4164 if (e
->data
) e
->data
+= e
->stride
* SrcStartIndex
;
4168 hr
= process_vertices_strided(This
, DestIndex
, VertexCount
, &stream_info
,
4169 (struct wined3d_buffer
*)pDestBuffer
, Flags
, DestFVF
);
4171 context_release(context
);
4177 * Get / Set Texture Stage States
4178 * TODO: Verify against dx9 definitions
4180 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD Value
) {
4181 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4182 DWORD oldValue
= This
->updateStateBlock
->textureState
[Stage
][Type
];
4184 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This
, Stage
, debug_d3dtexturestate(Type
), Type
, Value
);
4186 if (Stage
>= MAX_TEXTURES
) {
4187 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage
, MAX_TEXTURES
- 1);
4191 This
->updateStateBlock
->changed
.textureState
[Stage
] |= 1 << Type
;
4192 This
->updateStateBlock
->textureState
[Stage
][Type
] = Value
;
4194 if (This
->isRecordingState
) {
4195 TRACE("Recording... not performing anything\n");
4199 /* Checked after the assignments to allow proper stateblock recording */
4200 if(oldValue
== Value
) {
4201 TRACE("App is setting the old value over, nothing to do\n");
4205 if(Stage
> This
->stateBlock
->lowest_disabled_stage
&&
4206 This
->StateTable
[STATE_TEXTURESTAGE(0, Type
)].representative
== STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP
)) {
4207 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4208 * Changes in other states are important on disabled stages too
4213 if(Type
== WINED3DTSS_COLOROP
) {
4216 if(Value
== WINED3DTOP_DISABLE
&& oldValue
!= WINED3DTOP_DISABLE
) {
4217 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4218 * they have to be disabled
4220 * The current stage is dirtified below.
4222 for(i
= Stage
+ 1; i
< This
->stateBlock
->lowest_disabled_stage
; i
++) {
4223 TRACE("Additionally dirtifying stage %u\n", i
);
4224 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
4226 This
->stateBlock
->lowest_disabled_stage
= Stage
;
4227 TRACE("New lowest disabled: %u\n", Stage
);
4228 } else if(Value
!= WINED3DTOP_DISABLE
&& oldValue
== WINED3DTOP_DISABLE
) {
4229 /* Previously disabled stage enabled. Stages above it may need enabling
4230 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4231 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4233 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4236 for (i
= Stage
+ 1; i
< This
->adapter
->gl_info
.limits
.texture_stages
; ++i
)
4238 if(This
->updateStateBlock
->textureState
[i
][WINED3DTSS_COLOROP
] == WINED3DTOP_DISABLE
) {
4241 TRACE("Additionally dirtifying stage %u due to enable\n", i
);
4242 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
4244 This
->stateBlock
->lowest_disabled_stage
= i
;
4245 TRACE("New lowest disabled: %u\n", i
);
4249 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, Type
));
4254 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD
* pValue
) {
4255 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4256 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This
, Stage
, Type
, This
->updateStateBlock
->textureState
[Stage
][Type
]);
4257 *pValue
= This
->updateStateBlock
->textureState
[Stage
][Type
];
4264 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTexture(IWineD3DDevice
*iface
,
4265 DWORD stage
, IWineD3DBaseTexture
*texture
)
4267 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4268 IWineD3DBaseTexture
*prev
;
4270 TRACE("iface %p, stage %u, texture %p.\n", iface
, stage
, texture
);
4272 if (stage
>= WINED3DVERTEXTEXTURESAMPLER0
&& stage
<= WINED3DVERTEXTEXTURESAMPLER3
)
4273 stage
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
4275 /* Windows accepts overflowing this array... we do not. */
4276 if (stage
>= sizeof(This
->stateBlock
->textures
) / sizeof(*This
->stateBlock
->textures
))
4278 WARN("Ignoring invalid stage %u.\n", stage
);
4282 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4283 if (texture
&& ((IWineD3DTextureImpl
*)texture
)->resource
.pool
== WINED3DPOOL_SCRATCH
)
4285 WARN("Rejecting attempt to set scratch texture.\n");
4286 return WINED3DERR_INVALIDCALL
;
4289 This
->updateStateBlock
->changed
.textures
|= 1 << stage
;
4291 prev
= This
->updateStateBlock
->textures
[stage
];
4292 TRACE("Previous texture %p.\n", prev
);
4294 if (texture
== prev
)
4296 TRACE("App is setting the same texture again, nothing to do.\n");
4300 TRACE("Setting new texture to %p.\n", texture
);
4301 This
->updateStateBlock
->textures
[stage
] = texture
;
4303 if (This
->isRecordingState
)
4305 TRACE("Recording... not performing anything\n");
4307 if (texture
) IWineD3DBaseTexture_AddRef(texture
);
4308 if (prev
) IWineD3DBaseTexture_Release(prev
);
4315 IWineD3DBaseTextureImpl
*t
= (IWineD3DBaseTextureImpl
*)texture
;
4316 LONG bind_count
= InterlockedIncrement(&t
->baseTexture
.bindCount
);
4317 UINT dimensions
= IWineD3DBaseTexture_GetTextureDimensions(texture
);
4319 IWineD3DBaseTexture_AddRef(texture
);
4321 if (!prev
|| dimensions
!= IWineD3DBaseTexture_GetTextureDimensions(prev
))
4323 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADER
);
4326 if (!prev
&& stage
< MAX_TEXTURES
)
4328 /* The source arguments for color and alpha ops have different
4329 * meanings when a NULL texture is bound, so the COLOROP and
4330 * ALPHAOP have to be dirtified. */
4331 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, WINED3DTSS_COLOROP
));
4332 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, WINED3DTSS_ALPHAOP
));
4335 if (bind_count
== 1) t
->baseTexture
.sampler
= stage
;
4340 IWineD3DBaseTextureImpl
*t
= (IWineD3DBaseTextureImpl
*)prev
;
4341 LONG bind_count
= InterlockedDecrement(&t
->baseTexture
.bindCount
);
4343 IWineD3DBaseTexture_Release(prev
);
4345 if (!texture
&& stage
< MAX_TEXTURES
)
4347 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, WINED3DTSS_COLOROP
));
4348 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, WINED3DTSS_ALPHAOP
));
4351 if (bind_count
&& t
->baseTexture
.sampler
== stage
)
4355 /* Search for other stages the texture is bound to. Shouldn't
4356 * happen if applications bind textures to a single stage only. */
4357 TRACE("Searching for other stages the texture is bound to.\n");
4358 for (i
= 0; i
< MAX_COMBINED_SAMPLERS
; ++i
)
4360 if (This
->updateStateBlock
->textures
[i
] == prev
)
4362 TRACE("Texture is also bound to stage %u.\n", i
);
4363 t
->baseTexture
.sampler
= i
;
4370 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(stage
));
4375 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTexture(IWineD3DDevice
*iface
, DWORD Stage
, IWineD3DBaseTexture
** ppTexture
) {
4376 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4378 TRACE("(%p) : Stage %#x, ppTexture %p\n", This
, Stage
, ppTexture
);
4380 if (Stage
>= WINED3DVERTEXTEXTURESAMPLER0
&& Stage
<= WINED3DVERTEXTEXTURESAMPLER3
) {
4381 Stage
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
4384 if (Stage
>= sizeof(This
->stateBlock
->textures
)/sizeof(This
->stateBlock
->textures
[0])) {
4385 ERR("Current stage overflows textures array (stage %d)\n", Stage
);
4386 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
4389 *ppTexture
=This
->stateBlock
->textures
[Stage
];
4391 IWineD3DBaseTexture_AddRef(*ppTexture
);
4393 TRACE("(%p) : Returning %p\n", This
, *ppTexture
);
4401 static HRESULT WINAPI
IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice
*iface
, UINT iSwapChain
, UINT BackBuffer
, WINED3DBACKBUFFER_TYPE Type
,
4402 IWineD3DSurface
**ppBackBuffer
) {
4403 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4404 IWineD3DSwapChain
*swapChain
;
4407 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This
, BackBuffer
, Type
, iSwapChain
, *ppBackBuffer
);
4409 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
4410 if (hr
== WINED3D_OK
) {
4411 hr
= IWineD3DSwapChain_GetBackBuffer(swapChain
, BackBuffer
, Type
, ppBackBuffer
);
4412 IWineD3DSwapChain_Release(swapChain
);
4414 *ppBackBuffer
= NULL
;
4419 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice
*iface
, WINED3DCAPS
* pCaps
) {
4420 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4421 WARN("(%p) : stub, calling idirect3d for now\n", This
);
4422 return IWineD3D_GetDeviceCaps(This
->wined3d
, This
->adapter
->ordinal
, This
->devType
, pCaps
);
4425 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DDISPLAYMODE
* pMode
) {
4426 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4427 IWineD3DSwapChain
*swapChain
;
4430 if(iSwapChain
> 0) {
4431 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
4432 if (hr
== WINED3D_OK
) {
4433 hr
= IWineD3DSwapChain_GetDisplayMode(swapChain
, pMode
);
4434 IWineD3DSwapChain_Release(swapChain
);
4436 FIXME("(%p) Error getting display mode\n", This
);
4439 /* Don't read the real display mode,
4440 but return the stored mode instead. X11 can't change the color
4441 depth, and some apps are pretty angry if they SetDisplayMode from
4442 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4444 Also don't relay to the swapchain because with ddraw it's possible
4445 that there isn't a swapchain at all */
4446 pMode
->Width
= This
->ddraw_width
;
4447 pMode
->Height
= This
->ddraw_height
;
4448 pMode
->Format
= This
->ddraw_format
;
4449 pMode
->RefreshRate
= 0;
4457 * Stateblock related functions
4460 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice
*iface
) {
4461 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4462 IWineD3DStateBlock
*stateblock
;
4465 TRACE("(%p)\n", This
);
4467 if (This
->isRecordingState
) return WINED3DERR_INVALIDCALL
;
4469 hr
= IWineD3DDeviceImpl_CreateStateBlock(iface
, WINED3DSBT_RECORDED
, &stateblock
, NULL
);
4470 if (FAILED(hr
)) return hr
;
4472 IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
);
4473 This
->updateStateBlock
= (IWineD3DStateBlockImpl
*)stateblock
;
4474 This
->isRecordingState
= TRUE
;
4476 TRACE("(%p) recording stateblock %p\n", This
, stateblock
);
4481 static HRESULT WINAPI
IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice
*iface
, IWineD3DStateBlock
** ppStateBlock
) {
4482 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4483 IWineD3DStateBlockImpl
*object
= This
->updateStateBlock
;
4485 if (!This
->isRecordingState
) {
4486 WARN("(%p) not recording! returning error\n", This
);
4487 *ppStateBlock
= NULL
;
4488 return WINED3DERR_INVALIDCALL
;
4491 stateblock_init_contained_states(object
);
4493 *ppStateBlock
= (IWineD3DStateBlock
*) object
;
4494 This
->isRecordingState
= FALSE
;
4495 This
->updateStateBlock
= This
->stateBlock
;
4496 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
4497 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4498 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This
, *ppStateBlock
);
4503 * Scene related functions
4505 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginScene(IWineD3DDevice
*iface
) {
4506 /* At the moment we have no need for any functionality at the beginning
4508 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4509 TRACE("(%p)\n", This
);
4512 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4513 return WINED3DERR_INVALIDCALL
;
4515 This
->inScene
= TRUE
;
4519 static HRESULT WINAPI
IWineD3DDeviceImpl_EndScene(IWineD3DDevice
*iface
)
4521 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4522 struct wined3d_context
*context
;
4524 TRACE("(%p)\n", This
);
4526 if(!This
->inScene
) {
4527 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4528 return WINED3DERR_INVALIDCALL
;
4531 context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
4532 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4534 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4536 context_release(context
);
4538 This
->inScene
= FALSE
;
4542 static HRESULT WINAPI
IWineD3DDeviceImpl_Present(IWineD3DDevice
*iface
,
4543 CONST RECT
* pSourceRect
, CONST RECT
* pDestRect
,
4544 HWND hDestWindowOverride
, CONST RGNDATA
* pDirtyRegion
) {
4545 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4546 IWineD3DSwapChain
*swapChain
= NULL
;
4548 int swapchains
= IWineD3DDeviceImpl_GetNumberOfSwapChains(iface
);
4550 TRACE("(%p) Presenting the frame\n", This
);
4552 for(i
= 0 ; i
< swapchains
; i
++) {
4554 IWineD3DDeviceImpl_GetSwapChain(iface
, i
, &swapChain
);
4555 TRACE("presentinng chain %d, %p\n", i
, swapChain
);
4556 IWineD3DSwapChain_Present(swapChain
, pSourceRect
, pDestRect
, hDestWindowOverride
, pDirtyRegion
, 0);
4557 IWineD3DSwapChain_Release(swapChain
);
4563 /* Not called from the VTable (internal subroutine) */
4564 HRESULT
IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl
*This
, IWineD3DSurfaceImpl
*target
, DWORD Count
,
4565 CONST WINED3DRECT
* pRects
, DWORD Flags
, WINED3DCOLOR Color
,
4566 float Z
, DWORD Stencil
) {
4567 GLbitfield glMask
= 0;
4569 WINED3DRECT curRect
;
4571 const WINED3DVIEWPORT
*vp
= &This
->stateBlock
->viewport
;
4572 UINT drawable_width
, drawable_height
;
4573 IWineD3DSurfaceImpl
*depth_stencil
= (IWineD3DSurfaceImpl
*) This
->stencilBufferTarget
;
4574 IWineD3DSwapChainImpl
*swapchain
= NULL
;
4575 struct wined3d_context
*context
;
4577 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4578 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4579 * for the cleared parts, and the untouched parts.
4581 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4582 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4583 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4584 * checking all this if the dest surface is in the drawable anyway.
4586 if((Flags
& WINED3DCLEAR_TARGET
) && !(target
->Flags
& SFLAG_INDRAWABLE
)) {
4588 if(vp
->X
!= 0 || vp
->Y
!= 0 ||
4589 vp
->Width
< target
->currentDesc
.Width
|| vp
->Height
< target
->currentDesc
.Height
) {
4590 IWineD3DSurface_LoadLocation((IWineD3DSurface
*) target
, SFLAG_INDRAWABLE
, NULL
);
4593 if(This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
] && (
4594 This
->stateBlock
->scissorRect
.left
> 0 || This
->stateBlock
->scissorRect
.top
> 0 ||
4595 This
->stateBlock
->scissorRect
.right
< target
->currentDesc
.Width
||
4596 This
->stateBlock
->scissorRect
.bottom
< target
->currentDesc
.Height
)) {
4597 IWineD3DSurface_LoadLocation((IWineD3DSurface
*) target
, SFLAG_INDRAWABLE
, NULL
);
4600 if(Count
> 0 && pRects
&& (
4601 pRects
[0].x1
> 0 || pRects
[0].y1
> 0 ||
4602 pRects
[0].x2
< target
->currentDesc
.Width
||
4603 pRects
[0].y2
< target
->currentDesc
.Height
)) {
4604 IWineD3DSurface_LoadLocation((IWineD3DSurface
*) target
, SFLAG_INDRAWABLE
, NULL
);
4611 context
= context_acquire(This
, (IWineD3DSurface
*)target
, CTXUSAGE_CLEAR
);
4613 target
->get_drawable_size(context
, &drawable_width
, &drawable_height
);
4617 /* Only set the values up once, as they are not changing */
4618 if (Flags
& WINED3DCLEAR_STENCIL
) {
4619 glClearStencil(Stencil
);
4620 checkGLcall("glClearStencil");
4621 glMask
= glMask
| GL_STENCIL_BUFFER_BIT
;
4622 glStencilMask(0xFFFFFFFF);
4625 if (Flags
& WINED3DCLEAR_ZBUFFER
) {
4626 DWORD location
= context
->render_offscreen
? SFLAG_DS_OFFSCREEN
: SFLAG_DS_ONSCREEN
;
4627 glDepthMask(GL_TRUE
);
4629 checkGLcall("glClearDepth");
4630 glMask
= glMask
| GL_DEPTH_BUFFER_BIT
;
4631 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ZWRITEENABLE
));
4633 if (vp
->X
!= 0 || vp
->Y
!= 0 ||
4634 vp
->Width
< depth_stencil
->currentDesc
.Width
|| vp
->Height
< depth_stencil
->currentDesc
.Height
) {
4635 surface_load_ds_location(This
->stencilBufferTarget
, context
, location
);
4637 else if (This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
] && (
4638 This
->stateBlock
->scissorRect
.left
> 0 || This
->stateBlock
->scissorRect
.top
> 0 ||
4639 This
->stateBlock
->scissorRect
.right
< depth_stencil
->currentDesc
.Width
||
4640 This
->stateBlock
->scissorRect
.bottom
< depth_stencil
->currentDesc
.Height
)) {
4641 surface_load_ds_location(This
->stencilBufferTarget
, context
, location
);
4643 else if (Count
> 0 && pRects
&& (
4644 pRects
[0].x1
> 0 || pRects
[0].y1
> 0 ||
4645 pRects
[0].x2
< depth_stencil
->currentDesc
.Width
||
4646 pRects
[0].y2
< depth_stencil
->currentDesc
.Height
)) {
4647 surface_load_ds_location(This
->stencilBufferTarget
, context
, location
);
4651 if (Flags
& WINED3DCLEAR_TARGET
) {
4652 TRACE("Clearing screen with glClear to color %x\n", Color
);
4653 glClearColor(D3DCOLOR_R(Color
),
4657 checkGLcall("glClearColor");
4659 /* Clear ALL colors! */
4660 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
4661 glMask
= glMask
| GL_COLOR_BUFFER_BIT
;
4664 vp_rect
.left
= vp
->X
;
4665 vp_rect
.top
= vp
->Y
;
4666 vp_rect
.right
= vp
->X
+ vp
->Width
;
4667 vp_rect
.bottom
= vp
->Y
+ vp
->Height
;
4668 if (!(Count
> 0 && pRects
)) {
4669 if(This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
]) {
4670 IntersectRect(&vp_rect
, &vp_rect
, &This
->stateBlock
->scissorRect
);
4672 if (context
->render_offscreen
)
4674 glScissor(vp_rect
.left
, vp_rect
.top
,
4675 vp_rect
.right
- vp_rect
.left
, vp_rect
.bottom
- vp_rect
.top
);
4677 glScissor(vp_rect
.left
, drawable_height
- vp_rect
.bottom
,
4678 vp_rect
.right
- vp_rect
.left
, vp_rect
.bottom
- vp_rect
.top
);
4680 checkGLcall("glScissor");
4682 checkGLcall("glClear");
4684 /* Now process each rect in turn */
4685 for (i
= 0; i
< Count
; i
++) {
4686 /* Note gl uses lower left, width/height */
4687 IntersectRect((RECT
*)&curRect
, &vp_rect
, (const RECT
*)&pRects
[i
]);
4688 if(This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
]) {
4689 IntersectRect((RECT
*) &curRect
, (RECT
*) &curRect
, &This
->stateBlock
->scissorRect
);
4691 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This
,
4692 pRects
[i
].x1
, pRects
[i
].y1
, pRects
[i
].x2
, pRects
[i
].y2
,
4693 curRect
.x1
, (target
->currentDesc
.Height
- curRect
.y2
),
4694 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
4696 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4697 * The rectangle is not cleared, no error is returned, but further rectanlges are
4698 * still cleared if they are valid
4700 if(curRect
.x1
> curRect
.x2
|| curRect
.y1
> curRect
.y2
) {
4701 TRACE("Rectangle with negative dimensions, ignoring\n");
4705 if (context
->render_offscreen
)
4707 glScissor(curRect
.x1
, curRect
.y1
,
4708 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
4710 glScissor(curRect
.x1
, drawable_height
- curRect
.y2
,
4711 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
4713 checkGLcall("glScissor");
4716 checkGLcall("glClear");
4720 /* Restore the old values (why..?) */
4721 if (Flags
& WINED3DCLEAR_STENCIL
) {
4722 glStencilMask(This
->stateBlock
->renderState
[WINED3DRS_STENCILWRITEMASK
]);
4724 if (Flags
& WINED3DCLEAR_TARGET
) {
4725 DWORD mask
= This
->stateBlock
->renderState
[WINED3DRS_COLORWRITEENABLE
];
4726 glColorMask(mask
& WINED3DCOLORWRITEENABLE_RED
? GL_TRUE
: GL_FALSE
,
4727 mask
& WINED3DCOLORWRITEENABLE_GREEN
? GL_TRUE
: GL_FALSE
,
4728 mask
& WINED3DCOLORWRITEENABLE_BLUE
? GL_TRUE
: GL_FALSE
,
4729 mask
& WINED3DCOLORWRITEENABLE_ALPHA
? GL_TRUE
: GL_FALSE
);
4731 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4732 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4734 IWineD3DSurface_ModifyLocation((IWineD3DSurface
*)target
, SFLAG_INDRAWABLE
, TRUE
);
4736 if (Flags
& WINED3DCLEAR_ZBUFFER
) {
4737 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
4738 DWORD location
= context
->render_offscreen
? SFLAG_DS_OFFSCREEN
: SFLAG_DS_ONSCREEN
;
4739 surface_modify_ds_location(This
->stencilBufferTarget
, location
);
4744 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface
*)target
, &IID_IWineD3DSwapChain
, (void **)&swapchain
))) {
4745 if (target
== (IWineD3DSurfaceImpl
*) swapchain
->frontBuffer
) {
4748 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
4751 context_release(context
);
4756 static HRESULT WINAPI
IWineD3DDeviceImpl_Clear(IWineD3DDevice
*iface
, DWORD Count
, CONST WINED3DRECT
* pRects
,
4757 DWORD Flags
, WINED3DCOLOR Color
, float Z
, DWORD Stencil
) {
4758 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4759 IWineD3DSurfaceImpl
*target
= (IWineD3DSurfaceImpl
*)This
->render_targets
[0];
4761 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This
,
4762 Count
, pRects
, Flags
, Color
, Z
, Stencil
);
4764 if(Flags
& (WINED3DCLEAR_ZBUFFER
| WINED3DCLEAR_STENCIL
) && This
->stencilBufferTarget
== NULL
) {
4765 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4766 /* TODO: What about depth stencil buffers without stencil bits? */
4767 return WINED3DERR_INVALIDCALL
;
4770 return IWineD3DDeviceImpl_ClearSurface(This
, target
, Count
, pRects
, Flags
, Color
, Z
, Stencil
);
4777 static void WINAPI
IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice
*iface
,
4778 WINED3DPRIMITIVETYPE primitive_type
)
4780 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4782 TRACE("iface %p, primitive_type %s\n", iface
, debug_d3dprimitivetype(primitive_type
));
4784 This
->updateStateBlock
->changed
.primitive_type
= TRUE
;
4785 This
->updateStateBlock
->gl_primitive_type
= gl_primitive_type_from_d3d(primitive_type
);
4788 static void WINAPI
IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice
*iface
,
4789 WINED3DPRIMITIVETYPE
*primitive_type
)
4791 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4793 TRACE("iface %p, primitive_type %p\n", iface
, primitive_type
);
4795 *primitive_type
= d3d_primitive_type_from_gl(This
->stateBlock
->gl_primitive_type
);
4797 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type
));
4800 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice
*iface
, UINT StartVertex
, UINT vertex_count
)
4802 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4804 TRACE("(%p) : start %u, count %u\n", This
, StartVertex
, vertex_count
);
4806 if(!This
->stateBlock
->vertexDecl
) {
4807 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
4808 return WINED3DERR_INVALIDCALL
;
4811 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4812 if(This
->stateBlock
->streamIsUP
) {
4813 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
4814 This
->stateBlock
->streamIsUP
= FALSE
;
4817 if(This
->stateBlock
->loadBaseVertexIndex
!= 0) {
4818 This
->stateBlock
->loadBaseVertexIndex
= 0;
4819 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
4821 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4822 drawPrimitive(iface
, vertex_count
, StartVertex
/* start_idx */, 0 /* indxSize */, NULL
/* indxData */);
4826 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice
*iface
, UINT startIndex
, UINT index_count
)
4828 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4830 IWineD3DBuffer
*pIB
;
4833 pIB
= This
->stateBlock
->pIndexData
;
4835 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4836 * without an index buffer set. (The first time at least...)
4837 * D3D8 simply dies, but I doubt it can do much harm to return
4838 * D3DERR_INVALIDCALL there as well. */
4839 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This
);
4840 return WINED3DERR_INVALIDCALL
;
4843 if(!This
->stateBlock
->vertexDecl
) {
4844 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
4845 return WINED3DERR_INVALIDCALL
;
4848 if(This
->stateBlock
->streamIsUP
) {
4849 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
4850 This
->stateBlock
->streamIsUP
= FALSE
;
4852 vbo
= ((struct wined3d_buffer
*) pIB
)->buffer_object
;
4854 TRACE("(%p) : startIndex %u, index count %u.\n", This
, startIndex
, index_count
);
4856 if (This
->stateBlock
->IndexFmt
== WINED3DFMT_R16_UINT
) {
4862 if(This
->stateBlock
->loadBaseVertexIndex
!= This
->stateBlock
->baseVertexIndex
) {
4863 This
->stateBlock
->loadBaseVertexIndex
= This
->stateBlock
->baseVertexIndex
;
4864 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
4867 drawPrimitive(iface
, index_count
, startIndex
, idxStride
,
4868 vbo
? NULL
: ((struct wined3d_buffer
*)pIB
)->resource
.allocatedMemory
);
4873 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice
*iface
, UINT vertex_count
,
4874 const void *pVertexStreamZeroData
, UINT VertexStreamZeroStride
)
4876 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4879 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4880 This
, vertex_count
, pVertexStreamZeroData
, VertexStreamZeroStride
);
4882 if(!This
->stateBlock
->vertexDecl
) {
4883 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
4884 return WINED3DERR_INVALIDCALL
;
4887 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4888 vb
= This
->stateBlock
->streamSource
[0];
4889 This
->stateBlock
->streamSource
[0] = (IWineD3DBuffer
*)pVertexStreamZeroData
;
4890 if (vb
) IWineD3DBuffer_Release(vb
);
4891 This
->stateBlock
->streamOffset
[0] = 0;
4892 This
->stateBlock
->streamStride
[0] = VertexStreamZeroStride
;
4893 This
->stateBlock
->streamIsUP
= TRUE
;
4894 This
->stateBlock
->loadBaseVertexIndex
= 0;
4896 /* TODO: Only mark dirty if drawing from a different UP address */
4897 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
4899 drawPrimitive(iface
, vertex_count
, 0 /* start_idx */, 0 /* indxSize*/, NULL
/* indxData */);
4901 /* MSDN specifies stream zero settings must be set to NULL */
4902 This
->stateBlock
->streamStride
[0] = 0;
4903 This
->stateBlock
->streamSource
[0] = NULL
;
4905 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4906 * the new stream sources or use UP drawing again
4911 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice
*iface
,
4912 UINT index_count
, const void *pIndexData
, WINED3DFORMAT IndexDataFormat
,
4913 const void *pVertexStreamZeroData
, UINT VertexStreamZeroStride
)
4916 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4920 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4921 This
, index_count
, pIndexData
, IndexDataFormat
, pVertexStreamZeroData
, VertexStreamZeroStride
);
4923 if(!This
->stateBlock
->vertexDecl
) {
4924 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
4925 return WINED3DERR_INVALIDCALL
;
4928 if (IndexDataFormat
== WINED3DFMT_R16_UINT
) {
4934 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4935 vb
= This
->stateBlock
->streamSource
[0];
4936 This
->stateBlock
->streamSource
[0] = (IWineD3DBuffer
*)pVertexStreamZeroData
;
4937 if (vb
) IWineD3DBuffer_Release(vb
);
4938 This
->stateBlock
->streamIsUP
= TRUE
;
4939 This
->stateBlock
->streamOffset
[0] = 0;
4940 This
->stateBlock
->streamStride
[0] = VertexStreamZeroStride
;
4942 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4943 This
->stateBlock
->baseVertexIndex
= 0;
4944 This
->stateBlock
->loadBaseVertexIndex
= 0;
4945 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4946 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
4947 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
4949 drawPrimitive(iface
, index_count
, 0 /* start_idx */, idxStride
, pIndexData
);
4951 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4952 This
->stateBlock
->streamSource
[0] = NULL
;
4953 This
->stateBlock
->streamStride
[0] = 0;
4954 ib
= This
->stateBlock
->pIndexData
;
4956 IWineD3DBuffer_Release(ib
);
4957 This
->stateBlock
->pIndexData
= NULL
;
4959 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4960 * SetStreamSource to specify a vertex buffer
4966 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice
*iface
,
4967 UINT vertex_count
, const WineDirect3DVertexStridedData
*DrawPrimStrideData
)
4969 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
4971 /* Mark the state dirty until we have nicer tracking
4972 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4975 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
4976 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
4977 This
->stateBlock
->baseVertexIndex
= 0;
4978 This
->up_strided
= DrawPrimStrideData
;
4979 drawPrimitive(iface
, vertex_count
, 0, 0, NULL
);
4980 This
->up_strided
= NULL
;
4984 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice
*iface
,
4985 UINT vertex_count
, const WineDirect3DVertexStridedData
*DrawPrimStrideData
,
4986 UINT NumVertices
, const void *pIndexData
, WINED3DFORMAT IndexDataFormat
)
4988 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
4989 DWORD idxSize
= (IndexDataFormat
== WINED3DFMT_R32_UINT
? 4 : 2);
4991 /* Mark the state dirty until we have nicer tracking
4992 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4995 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
4996 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
4997 This
->stateBlock
->streamIsUP
= TRUE
;
4998 This
->stateBlock
->baseVertexIndex
= 0;
4999 This
->up_strided
= DrawPrimStrideData
;
5000 drawPrimitive(iface
, vertex_count
, 0 /* start_idx */, idxSize
, pIndexData
);
5001 This
->up_strided
= NULL
;
5005 static HRESULT
IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice
*iface
, IWineD3DVolume
*pSourceVolume
, IWineD3DVolume
*pDestinationVolume
) {
5006 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5007 * not callable by the app directly no parameter validation checks are needed here.
5009 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5010 WINED3DLOCKED_BOX src
;
5011 WINED3DLOCKED_BOX dst
;
5013 TRACE("(%p)->(%p, %p)\n", This
, pSourceVolume
, pDestinationVolume
);
5015 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5016 * dirtification to improve loading performance.
5018 hr
= IWineD3DVolume_LockBox(pSourceVolume
, &src
, NULL
, WINED3DLOCK_READONLY
);
5019 if(FAILED(hr
)) return hr
;
5020 hr
= IWineD3DVolume_LockBox(pDestinationVolume
, &dst
, NULL
, WINED3DLOCK_DISCARD
);
5022 IWineD3DVolume_UnlockBox(pSourceVolume
);
5026 memcpy(dst
.pBits
, src
.pBits
, ((IWineD3DVolumeImpl
*) pDestinationVolume
)->resource
.size
);
5028 hr
= IWineD3DVolume_UnlockBox(pDestinationVolume
);
5030 IWineD3DVolume_UnlockBox(pSourceVolume
);
5032 hr
= IWineD3DVolume_UnlockBox(pSourceVolume
);
5037 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice
*iface
,
5038 IWineD3DBaseTexture
*src_texture
, IWineD3DBaseTexture
*dst_texture
)
5040 unsigned int level_count
, i
;
5041 WINED3DRESOURCETYPE type
;
5044 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface
, src_texture
, dst_texture
);
5046 /* Verify that the source and destination textures are non-NULL. */
5047 if (!src_texture
|| !dst_texture
)
5049 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
5050 return WINED3DERR_INVALIDCALL
;
5053 if (src_texture
== dst_texture
)
5055 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
5056 return WINED3DERR_INVALIDCALL
;
5059 /* Verify that the source and destination textures are the same type. */
5060 type
= IWineD3DBaseTexture_GetType(src_texture
);
5061 if (IWineD3DBaseTexture_GetType(dst_texture
) != type
)
5063 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
5064 return WINED3DERR_INVALIDCALL
;
5067 /* Check that both textures have the identical numbers of levels. */
5068 level_count
= IWineD3DBaseTexture_GetLevelCount(src_texture
);
5069 if (IWineD3DBaseTexture_GetLevelCount(dst_texture
) != level_count
)
5071 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
5072 return WINED3DERR_INVALIDCALL
;
5075 /* Make sure that the destination texture is loaded. */
5076 ((IWineD3DBaseTextureImpl
*)dst_texture
)->baseTexture
.internal_preload(dst_texture
, SRGB_RGB
);
5078 /* Update every surface level of the texture. */
5081 case WINED3DRTYPE_TEXTURE
:
5083 IWineD3DSurface
*src_surface
;
5084 IWineD3DSurface
*dst_surface
;
5086 for (i
= 0; i
< level_count
; ++i
)
5088 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)src_texture
, i
, &src_surface
);
5089 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)dst_texture
, i
, &dst_surface
);
5090 hr
= IWineD3DDevice_UpdateSurface(iface
, src_surface
, NULL
, dst_surface
, NULL
);
5091 IWineD3DSurface_Release(dst_surface
);
5092 IWineD3DSurface_Release(src_surface
);
5095 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr
);
5102 case WINED3DRTYPE_CUBETEXTURE
:
5104 IWineD3DSurface
*src_surface
;
5105 IWineD3DSurface
*dst_surface
;
5106 WINED3DCUBEMAP_FACES face
;
5108 for (i
= 0; i
< level_count
; ++i
)
5110 /* Update each cube face. */
5111 for (face
= WINED3DCUBEMAP_FACE_POSITIVE_X
; face
<= WINED3DCUBEMAP_FACE_NEGATIVE_Z
; ++face
)
5113 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)src_texture
,
5114 face
, i
, &src_surface
);
5115 if (FAILED(hr
)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face
, i
, hr
);
5116 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)dst_texture
,
5117 face
, i
, &dst_surface
);
5118 if (FAILED(hr
)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face
, i
, hr
);
5119 hr
= IWineD3DDevice_UpdateSurface(iface
, src_surface
, NULL
, dst_surface
, NULL
);
5120 IWineD3DSurface_Release(dst_surface
);
5121 IWineD3DSurface_Release(src_surface
);
5124 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr
);
5132 case WINED3DRTYPE_VOLUMETEXTURE
:
5134 IWineD3DVolume
*src_volume
;
5135 IWineD3DVolume
*dst_volume
;
5137 for (i
= 0; i
< level_count
; ++i
)
5139 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture
*)src_texture
, i
, &src_volume
);
5140 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture
*)dst_texture
, i
, &dst_volume
);
5141 hr
= IWineD3DDeviceImpl_UpdateVolume(iface
, src_volume
, dst_volume
);
5142 IWineD3DVolume_Release(dst_volume
);
5143 IWineD3DVolume_Release(src_volume
);
5146 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr
);
5154 FIXME("Unsupported texture type %#x.\n", type
);
5155 return WINED3DERR_INVALIDCALL
;
5161 static HRESULT WINAPI
IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice
*iface
,UINT iSwapChain
, IWineD3DSurface
*pDestSurface
) {
5162 IWineD3DSwapChain
*swapChain
;
5164 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
5165 if(hr
== WINED3D_OK
) {
5166 hr
= IWineD3DSwapChain_GetFrontBufferData(swapChain
, pDestSurface
);
5167 IWineD3DSwapChain_Release(swapChain
);
5172 static HRESULT WINAPI
IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice
*iface
, DWORD
* pNumPasses
) {
5173 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5174 IWineD3DBaseTextureImpl
*texture
;
5177 TRACE("(%p) : %p\n", This
, pNumPasses
);
5179 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++) {
5180 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MINFILTER
] == WINED3DTEXF_NONE
) {
5181 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i
);
5182 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER
;
5184 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MAGFILTER
] == WINED3DTEXF_NONE
) {
5185 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i
);
5186 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER
;
5189 texture
= (IWineD3DBaseTextureImpl
*) This
->stateBlock
->textures
[i
];
5190 if (!texture
|| texture
->resource
.format_desc
->Flags
& WINED3DFMT_FLAG_FILTERING
) continue;
5192 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MAGFILTER
] != WINED3DTEXF_POINT
) {
5193 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i
);
5196 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MINFILTER
] != WINED3DTEXF_POINT
) {
5197 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i
);
5200 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MIPFILTER
] != WINED3DTEXF_NONE
&&
5201 This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MIPFILTER
] != WINED3DTEXF_POINT
/* sic! */) {
5202 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i
);
5207 /* return a sensible default */
5210 TRACE("returning D3D_OK\n");
5214 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl
*device
)
5218 for (i
= 0; i
< MAX_COMBINED_SAMPLERS
; ++i
)
5220 IWineD3DBaseTextureImpl
*texture
= (IWineD3DBaseTextureImpl
*)device
->stateBlock
->textures
[i
];
5221 if (texture
&& (texture
->resource
.format_desc
->format
== WINED3DFMT_P8_UINT
5222 || texture
->resource
.format_desc
->format
== WINED3DFMT_P8_UINT_A8_UNORM
))
5224 IWineD3DDeviceImpl_MarkStateDirty(device
, STATE_SAMPLER(i
));
5229 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, CONST PALETTEENTRY
* pEntries
) {
5230 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5233 PALETTEENTRY
**palettes
;
5235 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5237 if (PaletteNumber
>= MAX_PALETTES
) {
5238 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This
, PaletteNumber
, MAX_PALETTES
);
5239 return WINED3DERR_INVALIDCALL
;
5242 if (PaletteNumber
>= This
->NumberOfPalettes
) {
5243 NewSize
= This
->NumberOfPalettes
;
5246 } while(PaletteNumber
>= NewSize
);
5247 palettes
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, This
->palettes
, sizeof(PALETTEENTRY
*) * NewSize
);
5249 ERR("Out of memory!\n");
5250 return E_OUTOFMEMORY
;
5252 This
->palettes
= palettes
;
5253 This
->NumberOfPalettes
= NewSize
;
5256 if (!This
->palettes
[PaletteNumber
]) {
5257 This
->palettes
[PaletteNumber
] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY
) * 256);
5258 if (!This
->palettes
[PaletteNumber
]) {
5259 ERR("Out of memory!\n");
5260 return E_OUTOFMEMORY
;
5264 for (j
= 0; j
< 256; ++j
) {
5265 This
->palettes
[PaletteNumber
][j
].peRed
= pEntries
[j
].peRed
;
5266 This
->palettes
[PaletteNumber
][j
].peGreen
= pEntries
[j
].peGreen
;
5267 This
->palettes
[PaletteNumber
][j
].peBlue
= pEntries
[j
].peBlue
;
5268 This
->palettes
[PaletteNumber
][j
].peFlags
= pEntries
[j
].peFlags
;
5270 if (PaletteNumber
== This
->currentPalette
) dirtify_p8_texture_samplers(This
);
5271 TRACE("(%p) : returning\n", This
);
5275 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, PALETTEENTRY
* pEntries
) {
5276 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5278 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5279 if (PaletteNumber
>= This
->NumberOfPalettes
|| !This
->palettes
[PaletteNumber
]) {
5280 /* What happens in such situation isn't documented; Native seems to silently abort
5281 on such conditions. Return Invalid Call. */
5282 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This
, PaletteNumber
, This
->NumberOfPalettes
);
5283 return WINED3DERR_INVALIDCALL
;
5285 for (j
= 0; j
< 256; ++j
) {
5286 pEntries
[j
].peRed
= This
->palettes
[PaletteNumber
][j
].peRed
;
5287 pEntries
[j
].peGreen
= This
->palettes
[PaletteNumber
][j
].peGreen
;
5288 pEntries
[j
].peBlue
= This
->palettes
[PaletteNumber
][j
].peBlue
;
5289 pEntries
[j
].peFlags
= This
->palettes
[PaletteNumber
][j
].peFlags
;
5291 TRACE("(%p) : returning\n", This
);
5295 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT PaletteNumber
) {
5296 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5297 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5298 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5299 (tested with reference rasterizer). Return Invalid Call. */
5300 if (PaletteNumber
>= This
->NumberOfPalettes
|| !This
->palettes
[PaletteNumber
]) {
5301 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This
, PaletteNumber
, This
->NumberOfPalettes
);
5302 return WINED3DERR_INVALIDCALL
;
5304 /*TODO: stateblocks */
5305 if (This
->currentPalette
!= PaletteNumber
) {
5306 This
->currentPalette
= PaletteNumber
;
5307 dirtify_p8_texture_samplers(This
);
5309 TRACE("(%p) : returning\n", This
);
5313 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT
* PaletteNumber
) {
5314 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5315 if (PaletteNumber
== NULL
) {
5316 WARN("(%p) : returning Invalid Call\n", This
);
5317 return WINED3DERR_INVALIDCALL
;
5319 /*TODO: stateblocks */
5320 *PaletteNumber
= This
->currentPalette
;
5321 TRACE("(%p) : returning %u\n", This
, *PaletteNumber
);
5325 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice
*iface
, BOOL bSoftware
) {
5326 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5330 FIXME("(%p) : stub\n", This
);
5334 This
->softwareVertexProcessing
= bSoftware
;
5339 static BOOL WINAPI
IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice
*iface
) {
5340 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5344 FIXME("(%p) : stub\n", This
);
5347 return This
->softwareVertexProcessing
;
5351 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DRASTER_STATUS
* pRasterStatus
) {
5352 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5353 IWineD3DSwapChain
*swapChain
;
5356 TRACE("(%p) : SwapChain %d returning %p\n", This
, iSwapChain
, pRasterStatus
);
5358 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
5359 if(hr
== WINED3D_OK
){
5360 hr
= IWineD3DSwapChain_GetRasterStatus(swapChain
, pRasterStatus
);
5361 IWineD3DSwapChain_Release(swapChain
);
5363 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This
);
5369 static HRESULT WINAPI
IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice
*iface
, float nSegments
) {
5370 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5372 if(nSegments
!= 0.0f
) {
5375 FIXME("(%p) : stub nSegments(%f)\n", This
, nSegments
);
5382 static float WINAPI
IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice
*iface
) {
5383 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5387 FIXME("(%p) : stub returning(%f)\n", This
, 0.0f
);
5393 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice
*iface
, IWineD3DSurface
*pSourceSurface
, CONST RECT
* pSourceRect
, IWineD3DSurface
*pDestinationSurface
, CONST POINT
* pDestPoint
) {
5394 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5395 /** TODO: remove casts to IWineD3DSurfaceImpl
5396 * NOTE: move code to surface to accomplish this
5397 ****************************************/
5398 IWineD3DSurfaceImpl
*pSrcSurface
= (IWineD3DSurfaceImpl
*)pSourceSurface
;
5399 IWineD3DSurfaceImpl
*dst_impl
= (IWineD3DSurfaceImpl
*)pDestinationSurface
;
5400 int srcWidth
, srcHeight
;
5401 unsigned int srcSurfaceWidth
, srcSurfaceHeight
, destSurfaceWidth
, destSurfaceHeight
;
5402 WINED3DFORMAT destFormat
, srcFormat
;
5404 int srcLeft
, destLeft
, destTop
;
5405 WINED3DPOOL srcPool
, destPool
;
5407 int rowoffset
= 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5408 const struct GlPixelFormatDesc
*src_format_desc
, *dst_format_desc
;
5412 CONVERT_TYPES convert
= NO_CONVERSION
;
5413 struct wined3d_context
*context
;
5415 WINED3DSURFACE_DESC winedesc
;
5417 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This
, pSourceSurface
, pSourceRect
, pDestinationSurface
, pDestPoint
);
5419 IWineD3DSurface_GetDesc(pSourceSurface
, &winedesc
);
5420 srcSurfaceWidth
= winedesc
.width
;
5421 srcSurfaceHeight
= winedesc
.height
;
5422 srcPool
= winedesc
.pool
;
5423 srcFormat
= winedesc
.format
;
5425 IWineD3DSurface_GetDesc(pDestinationSurface
, &winedesc
);
5426 destSurfaceWidth
= winedesc
.width
;
5427 destSurfaceHeight
= winedesc
.height
;
5428 destPool
= winedesc
.pool
;
5429 destFormat
= winedesc
.format
;
5430 destSize
= winedesc
.size
;
5432 if(srcPool
!= WINED3DPOOL_SYSTEMMEM
|| destPool
!= WINED3DPOOL_DEFAULT
){
5433 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface
, pDestinationSurface
);
5434 return WINED3DERR_INVALIDCALL
;
5437 /* This call loads the opengl surface directly, instead of copying the surface to the
5438 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5439 * copy in sysmem and use regular surface loading.
5441 d3dfmt_get_conv(dst_impl
, FALSE
, TRUE
, &dummy
, &dummy
, &dummy
, &convert
, &bpp
, FALSE
);
5442 if(convert
!= NO_CONVERSION
) {
5443 return IWineD3DSurface_BltFast(pDestinationSurface
,
5444 pDestPoint
? pDestPoint
->x
: 0,
5445 pDestPoint
? pDestPoint
->y
: 0,
5446 pSourceSurface
, pSourceRect
, 0);
5449 if (destFormat
== WINED3DFMT_UNKNOWN
) {
5450 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This
);
5451 IWineD3DSurface_SetFormat(pDestinationSurface
, srcFormat
);
5453 /* Get the update surface description */
5454 IWineD3DSurface_GetDesc(pDestinationSurface
, &winedesc
);
5457 context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
5460 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
5461 checkGLcall("glActiveTextureARB");
5464 /* Make sure the surface is loaded and up to date */
5465 surface_internal_preload(pDestinationSurface
, SRGB_RGB
);
5466 IWineD3DSurface_BindTexture(pDestinationSurface
, FALSE
);
5468 src_format_desc
= ((IWineD3DSurfaceImpl
*)pSrcSurface
)->resource
.format_desc
;
5469 dst_format_desc
= dst_impl
->resource
.format_desc
;
5471 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5472 srcWidth
= pSourceRect
? pSourceRect
->right
- pSourceRect
->left
: srcSurfaceWidth
;
5473 srcHeight
= pSourceRect
? pSourceRect
->bottom
- pSourceRect
->top
: srcSurfaceHeight
;
5474 srcLeft
= pSourceRect
? pSourceRect
->left
: 0;
5475 destLeft
= pDestPoint
? pDestPoint
->x
: 0;
5476 destTop
= pDestPoint
? pDestPoint
->y
: 0;
5479 /* This function doesn't support compressed textures
5480 the pitch is just bytesPerPixel * width */
5481 if(srcWidth
!= srcSurfaceWidth
|| srcLeft
){
5482 rowoffset
= srcSurfaceWidth
* src_format_desc
->byte_count
;
5483 offset
+= srcLeft
* src_format_desc
->byte_count
;
5484 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5486 /* TODO DXT formats */
5488 if(pSourceRect
!= NULL
&& pSourceRect
->top
!= 0){
5489 offset
+= pSourceRect
->top
* srcSurfaceWidth
* src_format_desc
->byte_count
;
5491 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5492 This
, dst_impl
->texture_level
, destLeft
, destTop
, srcWidth
, srcHeight
, dst_format_desc
->glFormat
,
5493 dst_format_desc
->glType
, IWineD3DSurface_GetData(pSourceSurface
), offset
);
5496 if (IWineD3DSurface_GetData(pSourceSurface
) == NULL
) {
5498 /* need to lock the surface to get the data */
5499 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5504 /* TODO: Cube and volume support */
5506 /* not a whole row so we have to do it a line at a time */
5509 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5510 const unsigned char* data
=((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface
)) + offset
;
5512 for (j
= destTop
; j
< (srcHeight
+ destTop
); ++j
)
5514 glTexSubImage2D(dst_impl
->texture_target
, dst_impl
->texture_level
, destLeft
, j
,
5515 srcWidth
, 1, dst_format_desc
->glFormat
, dst_format_desc
->glType
,data
);
5519 } else { /* Full width, so just write out the whole texture */
5520 const unsigned char* data
= ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface
)) + offset
;
5522 if (dst_format_desc
->Flags
& WINED3DFMT_FLAG_COMPRESSED
)
5524 if (destSurfaceHeight
!= srcHeight
|| destSurfaceWidth
!= srcWidth
)
5526 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across. */
5527 FIXME("Updating part of a compressed texture is not supported.\n");
5529 if (destFormat
!= srcFormat
)
5531 FIXME("Updating mixed format compressed textures is not supported.\n");
5535 GL_EXTCALL(glCompressedTexImage2DARB(dst_impl
->texture_target
, dst_impl
->texture_level
,
5536 dst_format_desc
->glInternal
, srcWidth
, srcHeight
, 0, destSize
, data
));
5541 glTexSubImage2D(dst_impl
->texture_target
, dst_impl
->texture_level
, destLeft
, destTop
,
5542 srcWidth
, srcHeight
, dst_format_desc
->glFormat
, dst_format_desc
->glType
, data
);
5545 checkGLcall("glTexSubImage2D");
5548 context_release(context
);
5550 IWineD3DSurface_ModifyLocation(pDestinationSurface
, SFLAG_INTEXTURE
, TRUE
);
5551 sampler
= This
->rev_tex_unit_map
[0];
5552 if (sampler
!= WINED3D_UNMAPPED_STAGE
)
5554 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(sampler
));
5560 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice
*iface
, UINT Handle
, CONST
float* pNumSegs
, CONST WINED3DRECTPATCH_INFO
* pRectPatchInfo
) {
5561 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5562 struct WineD3DRectPatch
*patch
;
5563 GLenum old_primitive_type
;
5567 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This
, Handle
, pNumSegs
, pRectPatchInfo
);
5569 if(!(Handle
|| pRectPatchInfo
)) {
5570 /* TODO: Write a test for the return value, thus the FIXME */
5571 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5572 return WINED3DERR_INVALIDCALL
;
5576 i
= PATCHMAP_HASHFUNC(Handle
);
5578 LIST_FOR_EACH(e
, &This
->patches
[i
]) {
5579 patch
= LIST_ENTRY(e
, struct WineD3DRectPatch
, entry
);
5580 if(patch
->Handle
== Handle
) {
5587 TRACE("Patch does not exist. Creating a new one\n");
5588 patch
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*patch
));
5589 patch
->Handle
= Handle
;
5590 list_add_head(&This
->patches
[i
], &patch
->entry
);
5592 TRACE("Found existing patch %p\n", patch
);
5595 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5596 * attributes we have to tesselate, read back, and draw. This needs a patch
5597 * management structure instance. Create one.
5599 * A possible improvement is to check if a vertex shader is used, and if not directly
5602 FIXME("Drawing an uncached patch. This is slow\n");
5603 patch
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*patch
));
5606 if(pNumSegs
[0] != patch
->numSegs
[0] || pNumSegs
[1] != patch
->numSegs
[1] ||
5607 pNumSegs
[2] != patch
->numSegs
[2] || pNumSegs
[3] != patch
->numSegs
[3] ||
5608 (pRectPatchInfo
&& memcmp(pRectPatchInfo
, &patch
->RectPatchInfo
, sizeof(*pRectPatchInfo
)) != 0) ) {
5610 TRACE("Tesselation density or patch info changed, retesselating\n");
5612 if(pRectPatchInfo
) {
5613 patch
->RectPatchInfo
= *pRectPatchInfo
;
5615 patch
->numSegs
[0] = pNumSegs
[0];
5616 patch
->numSegs
[1] = pNumSegs
[1];
5617 patch
->numSegs
[2] = pNumSegs
[2];
5618 patch
->numSegs
[3] = pNumSegs
[3];
5620 hr
= tesselate_rectpatch(This
, patch
);
5622 WARN("Patch tesselation failed\n");
5624 /* Do not release the handle to store the params of the patch */
5626 HeapFree(GetProcessHeap(), 0, patch
);
5632 This
->currentPatch
= patch
;
5633 old_primitive_type
= This
->stateBlock
->gl_primitive_type
;
5634 This
->stateBlock
->gl_primitive_type
= GL_TRIANGLES
;
5635 IWineD3DDevice_DrawPrimitiveStrided(iface
, patch
->numSegs
[0] * patch
->numSegs
[1] * 2 * 3, &patch
->strided
);
5636 This
->stateBlock
->gl_primitive_type
= old_primitive_type
;
5637 This
->currentPatch
= NULL
;
5639 /* Destroy uncached patches */
5641 HeapFree(GetProcessHeap(), 0, patch
->mem
);
5642 HeapFree(GetProcessHeap(), 0, patch
);
5647 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice
*iface
, UINT Handle
, CONST
float* pNumSegs
, CONST WINED3DTRIPATCH_INFO
* pTriPatchInfo
) {
5648 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5649 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This
, Handle
, pNumSegs
, pTriPatchInfo
);
5650 FIXME("(%p) : Stub\n", This
);
5654 static HRESULT WINAPI
IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice
*iface
, UINT Handle
) {
5655 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5657 struct WineD3DRectPatch
*patch
;
5659 TRACE("(%p) Handle(%d)\n", This
, Handle
);
5661 i
= PATCHMAP_HASHFUNC(Handle
);
5662 LIST_FOR_EACH(e
, &This
->patches
[i
]) {
5663 patch
= LIST_ENTRY(e
, struct WineD3DRectPatch
, entry
);
5664 if(patch
->Handle
== Handle
) {
5665 TRACE("Deleting patch %p\n", patch
);
5666 list_remove(&patch
->entry
);
5667 HeapFree(GetProcessHeap(), 0, patch
->mem
);
5668 HeapFree(GetProcessHeap(), 0, patch
);
5673 /* TODO: Write a test for the return value */
5674 FIXME("Attempt to destroy nonexistent patch\n");
5675 return WINED3DERR_INVALIDCALL
;
5678 static IWineD3DSwapChain
*get_swapchain(IWineD3DSurface
*target
) {
5680 IWineD3DSwapChain
*swapchain
;
5682 hr
= IWineD3DSurface_GetContainer(target
, &IID_IWineD3DSwapChain
, (void **)&swapchain
);
5683 if (SUCCEEDED(hr
)) {
5684 IWineD3DSwapChain_Release((IUnknown
*)swapchain
);
5691 static void color_fill_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*surface
,
5692 const WINED3DRECT
*rect
, const float color
[4])
5694 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5695 struct wined3d_context
*context
;
5696 IWineD3DSwapChain
*swapchain
;
5698 swapchain
= get_swapchain(surface
);
5699 if (!surface_is_offscreen(surface
)) {
5702 TRACE("Surface %p is onscreen\n", surface
);
5704 context
= context_acquire(This
, surface
, CTXUSAGE_RESOURCELOAD
);
5706 context_bind_fbo(context
, GL_FRAMEBUFFER
, NULL
);
5707 buffer
= surface_get_gl_buffer(surface
, swapchain
);
5708 glDrawBuffer(buffer
);
5709 checkGLcall("glDrawBuffer()");
5711 TRACE("Surface %p is offscreen\n", surface
);
5713 context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
5715 context_bind_fbo(context
, GL_FRAMEBUFFER
, &context
->dst_fbo
);
5716 context_attach_surface_fbo(context
, GL_FRAMEBUFFER
, 0, surface
);
5717 context_attach_depth_stencil_fbo(context
, GL_FRAMEBUFFER
, NULL
, FALSE
);
5721 glEnable(GL_SCISSOR_TEST
);
5722 if(surface_is_offscreen(surface
)) {
5723 glScissor(rect
->x1
, rect
->y1
, rect
->x2
- rect
->x1
, rect
->y2
- rect
->y1
);
5725 glScissor(rect
->x1
, ((IWineD3DSurfaceImpl
*)surface
)->currentDesc
.Height
- rect
->y2
,
5726 rect
->x2
- rect
->x1
, rect
->y2
- rect
->y1
);
5728 checkGLcall("glScissor");
5729 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SCISSORRECT
);
5731 glDisable(GL_SCISSOR_TEST
);
5733 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE
));
5735 glDisable(GL_BLEND
);
5736 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE
));
5738 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
5739 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE
));
5741 glClearColor(color
[0], color
[1], color
[2], color
[3]);
5742 glClear(GL_COLOR_BUFFER_BIT
);
5743 checkGLcall("glClear");
5745 if (swapchain
&& surface
== ((IWineD3DSwapChainImpl
*)swapchain
)->frontBuffer
5746 && ((IWineD3DSwapChainImpl
*)swapchain
)->backBuffer
) {
5747 glDrawBuffer(GL_BACK
);
5748 checkGLcall("glDrawBuffer()");
5752 context_release(context
);
5755 static inline DWORD
argb_to_fmt(DWORD color
, WINED3DFORMAT destfmt
) {
5756 unsigned int r
, g
, b
, a
;
5759 if (destfmt
== WINED3DFMT_B8G8R8A8_UNORM
5760 || destfmt
== WINED3DFMT_B8G8R8X8_UNORM
5761 || destfmt
== WINED3DFMT_B8G8R8_UNORM
)
5764 TRACE("Converting color %08x to format %s\n", color
, debug_d3dformat(destfmt
));
5766 a
= (color
& 0xff000000) >> 24;
5767 r
= (color
& 0x00ff0000) >> 16;
5768 g
= (color
& 0x0000ff00) >> 8;
5769 b
= (color
& 0x000000ff) >> 0;
5773 case WINED3DFMT_B5G6R5_UNORM
:
5774 if(r
== 0xff && g
== 0xff && b
== 0xff) return 0xffff;
5781 TRACE("Returning %08x\n", ret
);
5784 case WINED3DFMT_B5G5R5X1_UNORM
:
5785 case WINED3DFMT_B5G5R5A1_UNORM
:
5794 TRACE("Returning %08x\n", ret
);
5797 case WINED3DFMT_A8_UNORM
:
5798 TRACE("Returning %08x\n", a
);
5801 case WINED3DFMT_B4G4R4X4_UNORM
:
5802 case WINED3DFMT_B4G4R4A4_UNORM
:
5811 TRACE("Returning %08x\n", ret
);
5814 case WINED3DFMT_B2G3R3_UNORM
:
5821 TRACE("Returning %08x\n", ret
);
5824 case WINED3DFMT_R8G8B8X8_UNORM
:
5825 case WINED3DFMT_R8G8B8A8_UNORM
:
5830 TRACE("Returning %08x\n", ret
);
5833 case WINED3DFMT_B10G10R10A2_UNORM
:
5835 r
= (r
* 1024) / 256;
5836 g
= (g
* 1024) / 256;
5837 b
= (b
* 1024) / 256;
5842 TRACE("Returning %08x\n", ret
);
5845 case WINED3DFMT_R10G10B10A2_UNORM
:
5847 r
= (r
* 1024) / 256;
5848 g
= (g
* 1024) / 256;
5849 b
= (b
* 1024) / 256;
5854 TRACE("Returning %08x\n", ret
);
5858 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt
));
5863 static HRESULT WINAPI
IWineD3DDeviceImpl_ColorFill(IWineD3DDevice
*iface
, IWineD3DSurface
*pSurface
, CONST WINED3DRECT
* pRect
, WINED3DCOLOR color
) {
5864 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5865 IWineD3DSurfaceImpl
*surface
= (IWineD3DSurfaceImpl
*) pSurface
;
5867 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This
, pSurface
, pRect
, color
);
5869 if (surface
->resource
.pool
!= WINED3DPOOL_DEFAULT
&& surface
->resource
.pool
!= WINED3DPOOL_SYSTEMMEM
) {
5870 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5871 return WINED3DERR_INVALIDCALL
;
5874 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
5875 const float c
[4] = {D3DCOLOR_R(color
), D3DCOLOR_G(color
), D3DCOLOR_B(color
), D3DCOLOR_A(color
)};
5876 color_fill_fbo(iface
, pSurface
, pRect
, c
);
5879 /* Just forward this to the DirectDraw blitting engine */
5880 memset(&BltFx
, 0, sizeof(BltFx
));
5881 BltFx
.dwSize
= sizeof(BltFx
);
5882 BltFx
.u5
.dwFillColor
= argb_to_fmt(color
, surface
->resource
.format_desc
->format
);
5883 return IWineD3DSurface_Blt(pSurface
, (const RECT
*)pRect
, NULL
, NULL
,
5884 WINEDDBLT_COLORFILL
, &BltFx
, WINED3DTEXF_POINT
);
5888 static void WINAPI
IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice
*iface
,
5889 IWineD3DRendertargetView
*rendertarget_view
, const float color
[4])
5891 IWineD3DResource
*resource
;
5892 IWineD3DSurface
*surface
;
5895 hr
= IWineD3DRendertargetView_GetResource(rendertarget_view
, &resource
);
5898 ERR("Failed to get resource, hr %#x\n", hr
);
5902 if (IWineD3DResource_GetType(resource
) != WINED3DRTYPE_SURFACE
)
5904 FIXME("Only supported on surface resources\n");
5905 IWineD3DResource_Release(resource
);
5909 surface
= (IWineD3DSurface
*)resource
;
5911 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
)
5913 color_fill_fbo(iface
, surface
, NULL
, color
);
5920 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5922 c
= ((DWORD
)(color
[2] * 255.0f
));
5923 c
|= ((DWORD
)(color
[1] * 255.0f
)) << 8;
5924 c
|= ((DWORD
)(color
[0] * 255.0f
)) << 16;
5925 c
|= ((DWORD
)(color
[3] * 255.0f
)) << 24;
5927 /* Just forward this to the DirectDraw blitting engine */
5928 memset(&BltFx
, 0, sizeof(BltFx
));
5929 BltFx
.dwSize
= sizeof(BltFx
);
5930 BltFx
.u5
.dwFillColor
= argb_to_fmt(c
, ((IWineD3DSurfaceImpl
*)surface
)->resource
.format_desc
->format
);
5931 hr
= IWineD3DSurface_Blt(surface
, NULL
, NULL
, NULL
, WINEDDBLT_COLORFILL
, &BltFx
, WINED3DTEXF_POINT
);
5934 ERR("Blt failed, hr %#x\n", hr
);
5938 IWineD3DResource_Release(resource
);
5941 /* rendertarget and depth stencil functions */
5942 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice
* iface
,DWORD RenderTargetIndex
, IWineD3DSurface
**ppRenderTarget
) {
5943 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5945 if (RenderTargetIndex
>= This
->adapter
->gl_info
.limits
.buffers
)
5947 ERR("(%p) : Only %d render targets are supported.\n",
5948 This
, This
->adapter
->gl_info
.limits
.buffers
);
5949 return WINED3DERR_INVALIDCALL
;
5952 *ppRenderTarget
= This
->render_targets
[RenderTargetIndex
];
5953 TRACE("(%p) : RenderTarget %d Index returning %p\n", This
, RenderTargetIndex
, *ppRenderTarget
);
5954 /* Note inc ref on returned surface */
5955 if(*ppRenderTarget
!= NULL
)
5956 IWineD3DSurface_AddRef(*ppRenderTarget
);
5960 static HRESULT WINAPI
IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice
*iface
, IWineD3DSurface
*Front
, IWineD3DSurface
*Back
) {
5961 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5962 IWineD3DSurfaceImpl
*FrontImpl
= (IWineD3DSurfaceImpl
*) Front
;
5963 IWineD3DSurfaceImpl
*BackImpl
= (IWineD3DSurfaceImpl
*) Back
;
5964 IWineD3DSwapChainImpl
*Swapchain
;
5967 TRACE("(%p)->(%p,%p)\n", This
, FrontImpl
, BackImpl
);
5969 hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**) &Swapchain
);
5970 if(hr
!= WINED3D_OK
) {
5971 ERR("Can't get the swapchain\n");
5975 /* Make sure to release the swapchain */
5976 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) Swapchain
);
5978 if(FrontImpl
&& !(FrontImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) ) {
5979 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5980 return WINED3DERR_INVALIDCALL
;
5982 else if(BackImpl
&& !(BackImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)) {
5983 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5984 return WINED3DERR_INVALIDCALL
;
5987 if(Swapchain
->frontBuffer
!= Front
) {
5988 TRACE("Changing the front buffer from %p to %p\n", Swapchain
->frontBuffer
, Front
);
5990 if(Swapchain
->frontBuffer
)
5992 IWineD3DSurface_SetContainer(Swapchain
->frontBuffer
, NULL
);
5993 ((IWineD3DSurfaceImpl
*)Swapchain
->frontBuffer
)->Flags
&= ~SFLAG_SWAPCHAIN
;
5995 Swapchain
->frontBuffer
= Front
;
5997 if(Swapchain
->frontBuffer
) {
5998 IWineD3DSurface_SetContainer(Swapchain
->frontBuffer
, (IWineD3DBase
*) Swapchain
);
5999 ((IWineD3DSurfaceImpl
*)Swapchain
->frontBuffer
)->Flags
|= SFLAG_SWAPCHAIN
;
6003 if(Back
&& !Swapchain
->backBuffer
) {
6004 /* We need memory for the back buffer array - only one back buffer this way */
6005 Swapchain
->backBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DSurface
*));
6006 if(!Swapchain
->backBuffer
) {
6007 ERR("Out of memory\n");
6008 return E_OUTOFMEMORY
;
6012 if(Swapchain
->backBuffer
[0] != Back
) {
6013 TRACE("Changing the back buffer from %p to %p\n", Swapchain
->backBuffer
, Back
);
6015 /* What to do about the context here in the case of multithreading? Not sure.
6016 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6018 WARN("No active context?\n");
6021 if(!Swapchain
->backBuffer
[0]) {
6022 /* GL was told to draw to the front buffer at creation,
6025 glDrawBuffer(GL_BACK
);
6026 checkGLcall("glDrawBuffer(GL_BACK)");
6027 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6028 Swapchain
->presentParms
.BackBufferCount
= 1;
6030 /* That makes problems - disable for now */
6031 /* glDrawBuffer(GL_FRONT); */
6032 checkGLcall("glDrawBuffer(GL_FRONT)");
6033 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6034 Swapchain
->presentParms
.BackBufferCount
= 0;
6038 if(Swapchain
->backBuffer
[0])
6040 IWineD3DSurface_SetContainer(Swapchain
->backBuffer
[0], NULL
);
6041 ((IWineD3DSurfaceImpl
*)Swapchain
->backBuffer
[0])->Flags
&= ~SFLAG_SWAPCHAIN
;
6043 Swapchain
->backBuffer
[0] = Back
;
6045 if(Swapchain
->backBuffer
[0]) {
6046 IWineD3DSurface_SetContainer(Swapchain
->backBuffer
[0], (IWineD3DBase
*) Swapchain
);
6047 ((IWineD3DSurfaceImpl
*)Swapchain
->backBuffer
[0])->Flags
|= SFLAG_SWAPCHAIN
;
6049 HeapFree(GetProcessHeap(), 0, Swapchain
->backBuffer
);
6050 Swapchain
->backBuffer
= NULL
;
6058 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice
* iface
, IWineD3DSurface
**ppZStencilSurface
) {
6059 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6060 *ppZStencilSurface
= This
->stencilBufferTarget
;
6061 TRACE("(%p) : zStencilSurface returning %p\n", This
, *ppZStencilSurface
);
6063 if(*ppZStencilSurface
!= NULL
) {
6064 /* Note inc ref on returned surface */
6065 IWineD3DSurface_AddRef(*ppZStencilSurface
);
6068 return WINED3DERR_NOTFOUND
;
6072 void stretch_rect_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*src_surface
, WINED3DRECT
*src_rect
,
6073 IWineD3DSurface
*dst_surface
, WINED3DRECT
*dst_rect
, const WINED3DTEXTUREFILTERTYPE filter
, BOOL flip
)
6075 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6076 GLbitfield mask
= GL_COLOR_BUFFER_BIT
; /* TODO: Support blitting depth/stencil surfaces */
6077 IWineD3DSwapChain
*src_swapchain
, *dst_swapchain
;
6078 const struct wined3d_gl_info
*gl_info
;
6079 struct wined3d_context
*context
;
6081 POINT offset
= {0, 0};
6083 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6084 This
, src_surface
, src_rect
, dst_surface
, dst_rect
, debug_d3dtexturefiltertype(filter
), filter
, flip
);
6085 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
);
6086 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect
->x1
, dst_rect
->y1
, dst_rect
->x2
, dst_rect
->y2
);
6089 case WINED3DTEXF_LINEAR
:
6090 gl_filter
= GL_LINEAR
;
6094 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter
), filter
);
6095 case WINED3DTEXF_NONE
:
6096 case WINED3DTEXF_POINT
:
6097 gl_filter
= GL_NEAREST
;
6101 /* Attach src surface to src fbo */
6102 src_swapchain
= get_swapchain(src_surface
);
6103 dst_swapchain
= get_swapchain(dst_surface
);
6105 if (src_swapchain
) context
= context_acquire(This
, src_surface
, CTXUSAGE_RESOURCELOAD
);
6106 else if (dst_swapchain
) context
= context_acquire(This
, dst_surface
, CTXUSAGE_RESOURCELOAD
);
6107 else context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
6109 gl_info
= context
->gl_info
;
6111 if (!surface_is_offscreen(src_surface
)) {
6112 GLenum buffer
= surface_get_gl_buffer(src_surface
, src_swapchain
);
6114 TRACE("Source surface %p is onscreen\n", src_surface
);
6115 /* Make sure the drawable is up to date. In the offscreen case
6116 * attach_surface_fbo() implicitly takes care of this. */
6117 IWineD3DSurface_LoadLocation(src_surface
, SFLAG_INDRAWABLE
, NULL
);
6119 if(buffer
== GL_FRONT
) {
6122 ClientToScreen(((IWineD3DSwapChainImpl
*)src_swapchain
)->win_handle
, &offset
);
6123 GetClientRect(((IWineD3DSwapChainImpl
*)src_swapchain
)->win_handle
, &windowsize
);
6124 h
= windowsize
.bottom
- windowsize
.top
;
6125 src_rect
->x1
-= offset
.x
; src_rect
->x2
-=offset
.x
;
6126 src_rect
->y1
= offset
.y
+ h
- src_rect
->y1
;
6127 src_rect
->y2
= offset
.y
+ h
- src_rect
->y2
;
6129 src_rect
->y1
= ((IWineD3DSurfaceImpl
*)src_surface
)->currentDesc
.Height
- src_rect
->y1
;
6130 src_rect
->y2
= ((IWineD3DSurfaceImpl
*)src_surface
)->currentDesc
.Height
- src_rect
->y2
;
6134 context_bind_fbo(context
, GL_READ_FRAMEBUFFER
, NULL
);
6135 glReadBuffer(buffer
);
6136 checkGLcall("glReadBuffer()");
6138 TRACE("Source surface %p is offscreen\n", src_surface
);
6140 context_bind_fbo(context
, GL_READ_FRAMEBUFFER
, &context
->src_fbo
);
6141 context_attach_surface_fbo(context
, GL_READ_FRAMEBUFFER
, 0, src_surface
);
6142 glReadBuffer(GL_COLOR_ATTACHMENT0
);
6143 checkGLcall("glReadBuffer()");
6144 context_attach_depth_stencil_fbo(context
, GL_READ_FRAMEBUFFER
, NULL
, FALSE
);
6148 /* Attach dst surface to dst fbo */
6149 if (!surface_is_offscreen(dst_surface
)) {
6150 GLenum buffer
= surface_get_gl_buffer(dst_surface
, dst_swapchain
);
6152 TRACE("Destination surface %p is onscreen\n", dst_surface
);
6153 /* Make sure the drawable is up to date. In the offscreen case
6154 * attach_surface_fbo() implicitly takes care of this. */
6155 IWineD3DSurface_LoadLocation(dst_surface
, SFLAG_INDRAWABLE
, NULL
);
6157 if(buffer
== GL_FRONT
) {
6160 ClientToScreen(((IWineD3DSwapChainImpl
*)dst_swapchain
)->win_handle
, &offset
);
6161 GetClientRect(((IWineD3DSwapChainImpl
*)dst_swapchain
)->win_handle
, &windowsize
);
6162 h
= windowsize
.bottom
- windowsize
.top
;
6163 dst_rect
->x1
-= offset
.x
; dst_rect
->x2
-=offset
.x
;
6164 dst_rect
->y1
= offset
.y
+ h
- dst_rect
->y1
;
6165 dst_rect
->y2
= offset
.y
+ h
- dst_rect
->y2
;
6167 /* Screen coords = window coords, surface height = window height */
6168 dst_rect
->y1
= ((IWineD3DSurfaceImpl
*)dst_surface
)->currentDesc
.Height
- dst_rect
->y1
;
6169 dst_rect
->y2
= ((IWineD3DSurfaceImpl
*)dst_surface
)->currentDesc
.Height
- dst_rect
->y2
;
6173 context_bind_fbo(context
, GL_DRAW_FRAMEBUFFER
, NULL
);
6174 glDrawBuffer(buffer
);
6175 checkGLcall("glDrawBuffer()");
6177 TRACE("Destination surface %p is offscreen\n", dst_surface
);
6180 context_bind_fbo(context
, GL_DRAW_FRAMEBUFFER
, &context
->dst_fbo
);
6181 context_attach_surface_fbo(context
, GL_DRAW_FRAMEBUFFER
, 0, dst_surface
);
6182 glDrawBuffer(GL_COLOR_ATTACHMENT0
);
6183 checkGLcall("glDrawBuffer()");
6184 context_attach_depth_stencil_fbo(context
, GL_DRAW_FRAMEBUFFER
, NULL
, FALSE
);
6186 glDisable(GL_SCISSOR_TEST
);
6187 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE
));
6190 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
,
6191 dst_rect
->x1
, dst_rect
->y2
, dst_rect
->x2
, dst_rect
->y1
, mask
, gl_filter
);
6192 checkGLcall("glBlitFramebuffer()");
6194 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
,
6195 dst_rect
->x1
, dst_rect
->y1
, dst_rect
->x2
, dst_rect
->y2
, mask
, gl_filter
);
6196 checkGLcall("glBlitFramebuffer()");
6199 IWineD3DSurface_ModifyLocation(dst_surface
, SFLAG_INDRAWABLE
, TRUE
);
6201 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6202 if (dst_swapchain
&& dst_surface
== ((IWineD3DSwapChainImpl
*)dst_swapchain
)->frontBuffer
6203 && ((IWineD3DSwapChainImpl
*)dst_swapchain
)->backBuffer
) {
6204 glDrawBuffer(GL_BACK
);
6205 checkGLcall("glDrawBuffer()");
6209 context_release(context
);
6212 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice
*iface
, DWORD RenderTargetIndex
, IWineD3DSurface
*pRenderTarget
,
6213 BOOL set_viewport
) {
6214 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6216 TRACE("(%p) : Setting rendertarget %d to %p\n", This
, RenderTargetIndex
, pRenderTarget
);
6218 if (RenderTargetIndex
>= This
->adapter
->gl_info
.limits
.buffers
)
6220 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6221 This
, RenderTargetIndex
, This
->adapter
->gl_info
.limits
.buffers
);
6222 return WINED3DERR_INVALIDCALL
;
6225 /* MSDN says that null disables the render target
6226 but a device must always be associated with a render target
6227 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6229 if (RenderTargetIndex
== 0 && pRenderTarget
== NULL
) {
6230 FIXME("Trying to set render target 0 to NULL\n");
6231 return WINED3DERR_INVALIDCALL
;
6233 if (pRenderTarget
&& !(((IWineD3DSurfaceImpl
*)pRenderTarget
)->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)) {
6234 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
);
6235 return WINED3DERR_INVALIDCALL
;
6238 /* If we are trying to set what we already have, don't bother */
6239 if (pRenderTarget
== This
->render_targets
[RenderTargetIndex
]) {
6240 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6243 if(pRenderTarget
) IWineD3DSurface_AddRef(pRenderTarget
);
6244 if(This
->render_targets
[RenderTargetIndex
]) IWineD3DSurface_Release(This
->render_targets
[RenderTargetIndex
]);
6245 This
->render_targets
[RenderTargetIndex
] = pRenderTarget
;
6247 /* Render target 0 is special */
6248 if(RenderTargetIndex
== 0 && set_viewport
) {
6249 /* Finally, reset the viewport and scissor rect as the MSDN states.
6250 * Tests show that stateblock recording is ignored, the change goes
6251 * directly into the primary stateblock.
6253 This
->stateBlock
->viewport
.Height
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Height
;
6254 This
->stateBlock
->viewport
.Width
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Width
;
6255 This
->stateBlock
->viewport
.X
= 0;
6256 This
->stateBlock
->viewport
.Y
= 0;
6257 This
->stateBlock
->viewport
.MaxZ
= 1.0f
;
6258 This
->stateBlock
->viewport
.MinZ
= 0.0f
;
6259 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VIEWPORT
);
6261 This
->stateBlock
->scissorRect
.top
= 0;
6262 This
->stateBlock
->scissorRect
.left
= 0;
6263 This
->stateBlock
->scissorRect
.right
= This
->stateBlock
->viewport
.Width
;
6264 This
->stateBlock
->scissorRect
.bottom
= This
->stateBlock
->viewport
.Height
;
6265 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SCISSORRECT
);
6270 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice
*iface
, IWineD3DSurface
*pNewZStencil
) {
6271 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6272 HRESULT hr
= WINED3D_OK
;
6273 IWineD3DSurface
*tmp
;
6275 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This
, This
->stencilBufferTarget
, pNewZStencil
);
6277 if (pNewZStencil
== This
->stencilBufferTarget
) {
6278 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6280 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6281 * depending on the renter target implementation being used.
6282 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6283 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6284 * stencil buffer and incur an extra memory overhead
6285 ******************************************************/
6287 if (This
->stencilBufferTarget
) {
6288 if (((IWineD3DSwapChainImpl
*)This
->swapchains
[0])->presentParms
.Flags
& WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6289 || ((IWineD3DSurfaceImpl
*)This
->stencilBufferTarget
)->Flags
& SFLAG_DISCARD
) {
6290 surface_modify_ds_location(This
->stencilBufferTarget
, SFLAG_DS_DISCARDED
);
6292 struct wined3d_context
*context
= context_acquire(This
, This
->render_targets
[0], CTXUSAGE_RESOURCELOAD
);
6293 surface_load_ds_location(This
->stencilBufferTarget
, context
, SFLAG_DS_OFFSCREEN
);
6294 surface_modify_ds_location(This
->stencilBufferTarget
, SFLAG_DS_OFFSCREEN
);
6295 context_release(context
);
6299 tmp
= This
->stencilBufferTarget
;
6300 This
->stencilBufferTarget
= pNewZStencil
;
6301 /* should we be calling the parent or the wined3d surface? */
6302 if (NULL
!= This
->stencilBufferTarget
) IWineD3DSurface_AddRef(This
->stencilBufferTarget
);
6303 if (NULL
!= tmp
) IWineD3DSurface_Release(tmp
);
6306 if((!tmp
&& pNewZStencil
) || (!pNewZStencil
&& tmp
)) {
6307 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6308 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ZENABLE
));
6309 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_STENCILENABLE
));
6310 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_STENCILWRITEMASK
));
6317 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice
* iface
, UINT XHotSpot
,
6318 UINT YHotSpot
, IWineD3DSurface
*pCursorBitmap
) {
6319 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6320 /* TODO: the use of Impl is deprecated. */
6321 IWineD3DSurfaceImpl
* pSur
= (IWineD3DSurfaceImpl
*) pCursorBitmap
;
6322 WINED3DLOCKED_RECT lockedRect
;
6324 TRACE("(%p) : Spot Pos(%u,%u)\n", This
, XHotSpot
, YHotSpot
);
6326 /* some basic validation checks */
6327 if(This
->cursorTexture
) {
6328 struct wined3d_context
*context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
6330 glDeleteTextures(1, &This
->cursorTexture
);
6332 context_release(context
);
6333 This
->cursorTexture
= 0;
6336 if ( (pSur
->currentDesc
.Width
== 32) && (pSur
->currentDesc
.Height
== 32) )
6337 This
->haveHardwareCursor
= TRUE
;
6339 This
->haveHardwareCursor
= FALSE
;
6342 WINED3DLOCKED_RECT rect
;
6344 /* MSDN: Cursor must be A8R8G8B8 */
6345 if (pSur
->resource
.format_desc
->format
!= WINED3DFMT_B8G8R8A8_UNORM
)
6347 ERR("(%p) : surface(%p) has an invalid format\n", This
, pCursorBitmap
);
6348 return WINED3DERR_INVALIDCALL
;
6351 /* MSDN: Cursor must be smaller than the display mode */
6352 if(pSur
->currentDesc
.Width
> This
->ddraw_width
||
6353 pSur
->currentDesc
.Height
> This
->ddraw_height
) {
6354 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
);
6355 return WINED3DERR_INVALIDCALL
;
6358 if (!This
->haveHardwareCursor
) {
6359 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6361 /* Do not store the surface's pointer because the application may
6362 * release it after setting the cursor image. Windows doesn't
6363 * addref the set surface, so we can't do this either without
6364 * creating circular refcount dependencies. Copy out the gl texture
6367 This
->cursorWidth
= pSur
->currentDesc
.Width
;
6368 This
->cursorHeight
= pSur
->currentDesc
.Height
;
6369 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap
, &rect
, NULL
, WINED3DLOCK_READONLY
)))
6371 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
6372 const struct GlPixelFormatDesc
*glDesc
= getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM
, gl_info
);
6373 struct wined3d_context
*context
;
6374 char *mem
, *bits
= rect
.pBits
;
6375 GLint intfmt
= glDesc
->glInternal
;
6376 GLint format
= glDesc
->glFormat
;
6377 GLint type
= glDesc
->glType
;
6378 INT height
= This
->cursorHeight
;
6379 INT width
= This
->cursorWidth
;
6380 INT bpp
= glDesc
->byte_count
;
6384 /* Reformat the texture memory (pitch and width can be
6386 mem
= HeapAlloc(GetProcessHeap(), 0, width
* height
* bpp
);
6387 for(i
= 0; i
< height
; i
++)
6388 memcpy(&mem
[width
* bpp
* i
], &bits
[rect
.Pitch
* i
], width
* bpp
);
6389 IWineD3DSurface_UnlockRect(pCursorBitmap
);
6391 context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
6395 if (gl_info
->supported
[APPLE_CLIENT_STORAGE
])
6397 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
6398 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6401 /* Make sure that a proper texture unit is selected */
6402 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
6403 checkGLcall("glActiveTextureARB");
6404 sampler
= This
->rev_tex_unit_map
[0];
6405 if (sampler
!= WINED3D_UNMAPPED_STAGE
)
6407 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(sampler
));
6409 /* Create a new cursor texture */
6410 glGenTextures(1, &This
->cursorTexture
);
6411 checkGLcall("glGenTextures");
6412 glBindTexture(GL_TEXTURE_2D
, This
->cursorTexture
);
6413 checkGLcall("glBindTexture");
6414 /* Copy the bitmap memory into the cursor texture */
6415 glTexImage2D(GL_TEXTURE_2D
, 0, intfmt
, width
, height
, 0, format
, type
, mem
);
6416 HeapFree(GetProcessHeap(), 0, mem
);
6417 checkGLcall("glTexImage2D");
6419 if (gl_info
->supported
[APPLE_CLIENT_STORAGE
])
6421 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
6422 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6427 context_release(context
);
6431 FIXME("A cursor texture was not returned.\n");
6432 This
->cursorTexture
= 0;
6437 /* Draw a hardware cursor */
6438 ICONINFO cursorInfo
;
6440 /* Create and clear maskBits because it is not needed for
6441 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6443 DWORD
*maskBits
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
6444 (pSur
->currentDesc
.Width
* pSur
->currentDesc
.Height
/ 8));
6445 IWineD3DSurface_LockRect(pCursorBitmap
, &lockedRect
, NULL
,
6446 WINED3DLOCK_NO_DIRTY_UPDATE
|
6447 WINED3DLOCK_READONLY
6449 TRACE("width: %i height: %i\n", pSur
->currentDesc
.Width
,
6450 pSur
->currentDesc
.Height
);
6452 cursorInfo
.fIcon
= FALSE
;
6453 cursorInfo
.xHotspot
= XHotSpot
;
6454 cursorInfo
.yHotspot
= YHotSpot
;
6455 cursorInfo
.hbmMask
= CreateBitmap(pSur
->currentDesc
.Width
, pSur
->currentDesc
.Height
,
6457 cursorInfo
.hbmColor
= CreateBitmap(pSur
->currentDesc
.Width
, pSur
->currentDesc
.Height
,
6458 1, 32, lockedRect
.pBits
);
6459 IWineD3DSurface_UnlockRect(pCursorBitmap
);
6460 /* Create our cursor and clean up. */
6461 cursor
= CreateIconIndirect(&cursorInfo
);
6463 if (cursorInfo
.hbmMask
) DeleteObject(cursorInfo
.hbmMask
);
6464 if (cursorInfo
.hbmColor
) DeleteObject(cursorInfo
.hbmColor
);
6465 if (This
->hardwareCursor
) DestroyCursor(This
->hardwareCursor
);
6466 This
->hardwareCursor
= cursor
;
6467 HeapFree(GetProcessHeap(), 0, maskBits
);
6471 This
->xHotSpot
= XHotSpot
;
6472 This
->yHotSpot
= YHotSpot
;
6476 static void WINAPI
IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice
* iface
, int XScreenSpace
, int YScreenSpace
, DWORD Flags
) {
6477 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6478 TRACE("(%p) : SetPos to (%u,%u)\n", This
, XScreenSpace
, YScreenSpace
);
6480 This
->xScreenSpace
= XScreenSpace
;
6481 This
->yScreenSpace
= YScreenSpace
;
6487 static BOOL WINAPI
IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice
* iface
, BOOL bShow
) {
6488 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6489 BOOL oldVisible
= This
->bCursorVisible
;
6492 TRACE("(%p) : visible(%d)\n", This
, bShow
);
6495 * When ShowCursor is first called it should make the cursor appear at the OS's last
6496 * known cursor position. Because of this, some applications just repetitively call
6497 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6500 This
->xScreenSpace
= pt
.x
;
6501 This
->yScreenSpace
= pt
.y
;
6503 if (This
->haveHardwareCursor
) {
6504 This
->bCursorVisible
= bShow
;
6506 SetCursor(This
->hardwareCursor
);
6512 if (This
->cursorTexture
)
6513 This
->bCursorVisible
= bShow
;
6519 static HRESULT WINAPI
evict_managed_resource(IWineD3DResource
*resource
, void *data
) {
6520 TRACE("checking resource %p for eviction\n", resource
);
6521 if(((IWineD3DResourceImpl
*) resource
)->resource
.pool
== WINED3DPOOL_MANAGED
) {
6522 TRACE("Evicting %p\n", resource
);
6523 IWineD3DResource_UnLoad(resource
);
6525 IWineD3DResource_Release(resource
);
6529 static HRESULT WINAPI
IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice
* iface
) {
6530 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6531 TRACE("(%p)\n", This
);
6533 IWineD3DDevice_EnumResources(iface
, evict_managed_resource
, NULL
);
6537 static HRESULT
updateSurfaceDesc(IWineD3DSurfaceImpl
*surface
, const WINED3DPRESENT_PARAMETERS
* pPresentationParameters
)
6539 IWineD3DDeviceImpl
*device
= surface
->resource
.wineD3DDevice
;
6540 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
6542 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6543 if(surface
->Flags
& SFLAG_DIBSECTION
) {
6544 /* Release the DC */
6545 SelectObject(surface
->hDC
, surface
->dib
.holdbitmap
);
6546 DeleteDC(surface
->hDC
);
6547 /* Release the DIB section */
6548 DeleteObject(surface
->dib
.DIBsection
);
6549 surface
->dib
.bitmap_data
= NULL
;
6550 surface
->resource
.allocatedMemory
= NULL
;
6551 surface
->Flags
&= ~SFLAG_DIBSECTION
;
6553 surface
->currentDesc
.Width
= pPresentationParameters
->BackBufferWidth
;
6554 surface
->currentDesc
.Height
= pPresentationParameters
->BackBufferHeight
;
6555 if (gl_info
->supported
[ARB_TEXTURE_NON_POWER_OF_TWO
] || gl_info
->supported
[ARB_TEXTURE_RECTANGLE
]
6556 || gl_info
->supported
[WINE_NORMALIZED_TEXRECT
])
6558 surface
->pow2Width
= pPresentationParameters
->BackBufferWidth
;
6559 surface
->pow2Height
= pPresentationParameters
->BackBufferHeight
;
6561 surface
->pow2Width
= surface
->pow2Height
= 1;
6562 while (surface
->pow2Width
< pPresentationParameters
->BackBufferWidth
) surface
->pow2Width
<<= 1;
6563 while (surface
->pow2Height
< pPresentationParameters
->BackBufferHeight
) surface
->pow2Height
<<= 1;
6565 surface
->glRect
.left
= 0;
6566 surface
->glRect
.top
= 0;
6567 surface
->glRect
.right
= surface
->pow2Width
;
6568 surface
->glRect
.bottom
= surface
->pow2Height
;
6570 if (surface
->texture_name
)
6572 struct wined3d_context
*context
= context_acquire(device
, NULL
, CTXUSAGE_RESOURCELOAD
);
6574 glDeleteTextures(1, &surface
->texture_name
);
6576 context_release(context
);
6577 surface
->texture_name
= 0;
6578 surface
->Flags
&= ~SFLAG_CLIENT
;
6580 if(surface
->pow2Width
!= pPresentationParameters
->BackBufferWidth
||
6581 surface
->pow2Height
!= pPresentationParameters
->BackBufferHeight
) {
6582 surface
->Flags
|= SFLAG_NONPOW2
;
6584 surface
->Flags
&= ~SFLAG_NONPOW2
;
6586 HeapFree(GetProcessHeap(), 0, surface
->resource
.heapMemory
);
6587 surface
->resource
.allocatedMemory
= NULL
;
6588 surface
->resource
.heapMemory
= NULL
;
6589 surface
->resource
.size
= IWineD3DSurface_GetPitch((IWineD3DSurface
*) surface
) * surface
->pow2Width
;
6591 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6593 if(!surface_init_sysmem((IWineD3DSurface
*) surface
))
6595 return E_OUTOFMEMORY
;
6600 static HRESULT WINAPI
reset_unload_resources(IWineD3DResource
*resource
, void *data
) {
6601 TRACE("Unloading resource %p\n", resource
);
6602 IWineD3DResource_UnLoad(resource
);
6603 IWineD3DResource_Release(resource
);
6607 static BOOL
is_display_mode_supported(IWineD3DDeviceImpl
*This
, const WINED3DPRESENT_PARAMETERS
*pp
)
6610 WINED3DDISPLAYMODE m
;
6613 /* All Windowed modes are supported, as is leaving the current mode */
6614 if(pp
->Windowed
) return TRUE
;
6615 if(!pp
->BackBufferWidth
) return TRUE
;
6616 if(!pp
->BackBufferHeight
) return TRUE
;
6618 count
= IWineD3D_GetAdapterModeCount(This
->wined3d
, This
->adapter
->ordinal
, WINED3DFMT_UNKNOWN
);
6619 for(i
= 0; i
< count
; i
++) {
6620 memset(&m
, 0, sizeof(m
));
6621 hr
= IWineD3D_EnumAdapterModes(This
->wined3d
, This
->adapter
->ordinal
, WINED3DFMT_UNKNOWN
, i
, &m
);
6623 ERR("EnumAdapterModes failed\n");
6625 if(m
.Width
== pp
->BackBufferWidth
&& m
.Height
== pp
->BackBufferHeight
) {
6626 /* Mode found, it is supported */
6630 /* Mode not found -> not supported */
6634 void delete_opengl_contexts(IWineD3DDevice
*iface
, IWineD3DSwapChain
*swapchain_iface
) {
6635 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6636 IWineD3DSwapChainImpl
*swapchain
= (IWineD3DSwapChainImpl
*) swapchain_iface
;
6637 const struct wined3d_gl_info
*gl_info
;
6638 struct wined3d_context
*context
;
6640 IWineD3DBaseShaderImpl
*shader
;
6642 context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
6643 gl_info
= context
->gl_info
;
6645 IWineD3DDevice_EnumResources(iface
, reset_unload_resources
, NULL
);
6646 LIST_FOR_EACH_ENTRY(shader
, &This
->shaders
, IWineD3DBaseShaderImpl
, baseShader
.shader_list_entry
) {
6647 This
->shader_backend
->shader_destroy((IWineD3DBaseShader
*) shader
);
6651 if(This
->depth_blt_texture
) {
6652 glDeleteTextures(1, &This
->depth_blt_texture
);
6653 This
->depth_blt_texture
= 0;
6655 if (This
->depth_blt_rb
) {
6656 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &This
->depth_blt_rb
);
6657 This
->depth_blt_rb
= 0;
6658 This
->depth_blt_rb_w
= 0;
6659 This
->depth_blt_rb_h
= 0;
6663 This
->blitter
->free_private(iface
);
6664 This
->frag_pipe
->free_private(iface
);
6665 This
->shader_backend
->shader_free_private(iface
);
6668 for (i
= 0; i
< This
->adapter
->gl_info
.limits
.textures
; ++i
)
6670 /* Textures are recreated below */
6671 glDeleteTextures(1, &This
->dummyTextureName
[i
]);
6672 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
6673 This
->dummyTextureName
[i
] = 0;
6677 context_release(context
);
6679 while (This
->numContexts
)
6681 context_destroy(This
, This
->contexts
[0]);
6683 HeapFree(GetProcessHeap(), 0, swapchain
->context
);
6684 swapchain
->context
= NULL
;
6685 swapchain
->num_contexts
= 0;
6688 HRESULT
create_primary_opengl_context(IWineD3DDevice
*iface
, IWineD3DSwapChain
*swapchain_iface
) {
6689 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6690 IWineD3DSwapChainImpl
*swapchain
= (IWineD3DSwapChainImpl
*) swapchain_iface
;
6692 IWineD3DSurfaceImpl
*target
;
6694 /* Recreate the primary swapchain's context */
6695 swapchain
->context
= HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain
->context
));
6696 if(swapchain
->backBuffer
) {
6697 target
= (IWineD3DSurfaceImpl
*) swapchain
->backBuffer
[0];
6699 target
= (IWineD3DSurfaceImpl
*) swapchain
->frontBuffer
;
6701 swapchain
->context
[0] = context_create(This
, target
, swapchain
->win_handle
, FALSE
, &swapchain
->presentParms
);
6702 swapchain
->num_contexts
= 1;
6703 swapchain
->context
[0]->render_offscreen
= swapchain
->render_to_fbo
;
6705 create_dummy_textures(This
);
6707 context_release(swapchain
->context
[0]);
6709 hr
= This
->shader_backend
->shader_alloc_private(iface
);
6711 ERR("Failed to recreate shader private data\n");
6714 hr
= This
->frag_pipe
->alloc_private(iface
);
6716 TRACE("Fragment pipeline private data couldn't be allocated\n");
6719 hr
= This
->blitter
->alloc_private(iface
);
6721 TRACE("Blitter private data couldn't be allocated\n");
6728 This
->blitter
->free_private(iface
);
6729 This
->frag_pipe
->free_private(iface
);
6730 This
->shader_backend
->shader_free_private(iface
);
6734 static HRESULT WINAPI
IWineD3DDeviceImpl_Reset(IWineD3DDevice
* iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
) {
6735 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6736 IWineD3DSwapChainImpl
*swapchain
;
6738 BOOL DisplayModeChanged
= FALSE
;
6739 WINED3DDISPLAYMODE mode
;
6740 TRACE("(%p)\n", This
);
6742 hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**) &swapchain
);
6744 ERR("Failed to get the first implicit swapchain\n");
6748 if(!is_display_mode_supported(This
, pPresentationParameters
)) {
6749 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6750 WARN("Requested mode: %d, %d\n", pPresentationParameters
->BackBufferWidth
,
6751 pPresentationParameters
->BackBufferHeight
);
6752 IWineD3DSwapChain_Release((IWineD3DSwapChain
*)swapchain
);
6753 return WINED3DERR_INVALIDCALL
;
6756 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6757 * on an existing gl context, so there's no real need for recreation.
6759 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6761 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6763 TRACE("New params:\n");
6764 TRACE("BackBufferWidth = %d\n", pPresentationParameters
->BackBufferWidth
);
6765 TRACE("BackBufferHeight = %d\n", pPresentationParameters
->BackBufferHeight
);
6766 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters
->BackBufferFormat
));
6767 TRACE("BackBufferCount = %d\n", pPresentationParameters
->BackBufferCount
);
6768 TRACE("MultiSampleType = %d\n", pPresentationParameters
->MultiSampleType
);
6769 TRACE("MultiSampleQuality = %d\n", pPresentationParameters
->MultiSampleQuality
);
6770 TRACE("SwapEffect = %d\n", pPresentationParameters
->SwapEffect
);
6771 TRACE("hDeviceWindow = %p\n", pPresentationParameters
->hDeviceWindow
);
6772 TRACE("Windowed = %s\n", pPresentationParameters
->Windowed
? "true" : "false");
6773 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters
->EnableAutoDepthStencil
? "true" : "false");
6774 TRACE("Flags = %08x\n", pPresentationParameters
->Flags
);
6775 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters
->FullScreen_RefreshRateInHz
);
6776 TRACE("PresentationInterval = %d\n", pPresentationParameters
->PresentationInterval
);
6778 /* No special treatment of these parameters. Just store them */
6779 swapchain
->presentParms
.SwapEffect
= pPresentationParameters
->SwapEffect
;
6780 swapchain
->presentParms
.Flags
= pPresentationParameters
->Flags
;
6781 swapchain
->presentParms
.PresentationInterval
= pPresentationParameters
->PresentationInterval
;
6782 swapchain
->presentParms
.FullScreen_RefreshRateInHz
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
6784 /* What to do about these? */
6785 if(pPresentationParameters
->BackBufferCount
!= 0 &&
6786 pPresentationParameters
->BackBufferCount
!= swapchain
->presentParms
.BackBufferCount
) {
6787 ERR("Cannot change the back buffer count yet\n");
6789 if(pPresentationParameters
->BackBufferFormat
!= WINED3DFMT_UNKNOWN
&&
6790 pPresentationParameters
->BackBufferFormat
!= swapchain
->presentParms
.BackBufferFormat
) {
6791 ERR("Cannot change the back buffer format yet\n");
6793 if(pPresentationParameters
->hDeviceWindow
!= NULL
&&
6794 pPresentationParameters
->hDeviceWindow
!= swapchain
->presentParms
.hDeviceWindow
) {
6795 ERR("Cannot change the device window yet\n");
6797 if (pPresentationParameters
->EnableAutoDepthStencil
&& !This
->auto_depth_stencil_buffer
) {
6800 TRACE("Creating the depth stencil buffer\n");
6802 hrc
= IWineD3DDeviceParent_CreateDepthStencilSurface(This
->device_parent
,
6804 pPresentationParameters
->BackBufferWidth
,
6805 pPresentationParameters
->BackBufferHeight
,
6806 pPresentationParameters
->AutoDepthStencilFormat
,
6807 pPresentationParameters
->MultiSampleType
,
6808 pPresentationParameters
->MultiSampleQuality
,
6810 &This
->auto_depth_stencil_buffer
);
6813 ERR("Failed to create the depth stencil buffer\n");
6814 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
6815 return WINED3DERR_INVALIDCALL
;
6819 /* Reset the depth stencil */
6820 if (pPresentationParameters
->EnableAutoDepthStencil
)
6821 IWineD3DDevice_SetDepthStencilSurface(iface
, This
->auto_depth_stencil_buffer
);
6823 IWineD3DDevice_SetDepthStencilSurface(iface
, NULL
);
6825 TRACE("Resetting stateblock\n");
6826 IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
);
6827 IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->stateBlock
);
6829 delete_opengl_contexts(iface
, (IWineD3DSwapChain
*) swapchain
);
6831 if(pPresentationParameters
->Windowed
) {
6832 mode
.Width
= swapchain
->orig_width
;
6833 mode
.Height
= swapchain
->orig_height
;
6834 mode
.RefreshRate
= 0;
6835 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
6837 mode
.Width
= pPresentationParameters
->BackBufferWidth
;
6838 mode
.Height
= pPresentationParameters
->BackBufferHeight
;
6839 mode
.RefreshRate
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
6840 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
6843 /* Should Width == 800 && Height == 0 set 800x600? */
6844 if(pPresentationParameters
->BackBufferWidth
!= 0 && pPresentationParameters
->BackBufferHeight
!= 0 &&
6845 (pPresentationParameters
->BackBufferWidth
!= swapchain
->presentParms
.BackBufferWidth
||
6846 pPresentationParameters
->BackBufferHeight
!= swapchain
->presentParms
.BackBufferHeight
))
6850 if(!pPresentationParameters
->Windowed
) {
6851 DisplayModeChanged
= TRUE
;
6853 swapchain
->presentParms
.BackBufferWidth
= pPresentationParameters
->BackBufferWidth
;
6854 swapchain
->presentParms
.BackBufferHeight
= pPresentationParameters
->BackBufferHeight
;
6856 hr
= updateSurfaceDesc((IWineD3DSurfaceImpl
*)swapchain
->frontBuffer
, pPresentationParameters
);
6859 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
6863 for(i
= 0; i
< swapchain
->presentParms
.BackBufferCount
; i
++) {
6864 hr
= updateSurfaceDesc((IWineD3DSurfaceImpl
*)swapchain
->backBuffer
[i
], pPresentationParameters
);
6867 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
6871 if(This
->auto_depth_stencil_buffer
) {
6872 hr
= updateSurfaceDesc((IWineD3DSurfaceImpl
*)This
->auto_depth_stencil_buffer
, pPresentationParameters
);
6875 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
6881 if((pPresentationParameters
->Windowed
&& !swapchain
->presentParms
.Windowed
) ||
6882 (swapchain
->presentParms
.Windowed
&& !pPresentationParameters
->Windowed
) ||
6883 DisplayModeChanged
) {
6885 IWineD3DDevice_SetDisplayMode(iface
, 0, &mode
);
6887 if(swapchain
->win_handle
&& !pPresentationParameters
->Windowed
) {
6888 if(swapchain
->presentParms
.Windowed
) {
6889 /* switch from windowed to fs */
6890 IWineD3DDeviceImpl_SetupFullscreenWindow(iface
, swapchain
->win_handle
,
6891 pPresentationParameters
->BackBufferWidth
,
6892 pPresentationParameters
->BackBufferHeight
);
6894 /* Fullscreen -> fullscreen mode change */
6895 MoveWindow(swapchain
->win_handle
, 0, 0,
6896 pPresentationParameters
->BackBufferWidth
, pPresentationParameters
->BackBufferHeight
,
6899 } else if(swapchain
->win_handle
&& !swapchain
->presentParms
.Windowed
) {
6900 /* Fullscreen -> windowed switch */
6901 IWineD3DDeviceImpl_RestoreWindow(iface
, swapchain
->win_handle
);
6903 swapchain
->presentParms
.Windowed
= pPresentationParameters
->Windowed
;
6904 } else if(!pPresentationParameters
->Windowed
) {
6905 DWORD style
= This
->style
, exStyle
= This
->exStyle
;
6906 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6907 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6908 * Reset to clear up their mess. Guild Wars also loses the device during that.
6912 IWineD3DDeviceImpl_SetupFullscreenWindow(iface
, swapchain
->win_handle
,
6913 pPresentationParameters
->BackBufferWidth
,
6914 pPresentationParameters
->BackBufferHeight
);
6915 This
->style
= style
;
6916 This
->exStyle
= exStyle
;
6919 /* Note: No parent needed for initial internal stateblock */
6920 hr
= IWineD3DDevice_CreateStateBlock(iface
, WINED3DSBT_INIT
, (IWineD3DStateBlock
**)&This
->stateBlock
, NULL
);
6921 if (FAILED(hr
)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr
);
6922 else TRACE("Created stateblock %p\n", This
->stateBlock
);
6923 This
->updateStateBlock
= This
->stateBlock
;
6924 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
6926 hr
= IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock
*) This
->stateBlock
);
6928 ERR("Resetting the stateblock failed with error 0x%08x\n", hr
);
6931 if(wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
)
6934 GetClientRect(swapchain
->win_handle
, &client_rect
);
6936 if(swapchain
->presentParms
.BackBufferWidth
!= client_rect
.right
||
6937 swapchain
->presentParms
.BackBufferHeight
!= client_rect
.bottom
)
6939 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6940 swapchain
->presentParms
.BackBufferWidth
,
6941 swapchain
->presentParms
.BackBufferHeight
,
6942 client_rect
.right
, client_rect
.bottom
);
6943 swapchain
->render_to_fbo
= TRUE
;
6947 TRACE("Rendering directly to GL_BACK\n");
6948 swapchain
->render_to_fbo
= FALSE
;
6952 hr
= create_primary_opengl_context(iface
, (IWineD3DSwapChain
*) swapchain
);
6953 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
6955 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6961 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice
*iface
, BOOL bEnableDialogs
) {
6962 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6963 /** FIXME: always true at the moment **/
6964 if(!bEnableDialogs
) {
6965 FIXME("(%p) Dialogs cannot be disabled yet\n", This
);
6971 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice
*iface
, WINED3DDEVICE_CREATION_PARAMETERS
*pParameters
) {
6972 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6973 TRACE("(%p) : pParameters %p\n", This
, pParameters
);
6975 *pParameters
= This
->createParms
;
6979 static void WINAPI
IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice
* iface
, UINT iSwapChain
, DWORD Flags
, CONST WINED3DGAMMARAMP
* pRamp
) {
6980 IWineD3DSwapChain
*swapchain
;
6982 TRACE("Relaying to swapchain\n");
6984 if (IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
) == WINED3D_OK
) {
6985 IWineD3DSwapChain_SetGammaRamp(swapchain
, Flags
, pRamp
);
6986 IWineD3DSwapChain_Release(swapchain
);
6991 static void WINAPI
IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DGAMMARAMP
* pRamp
) {
6992 IWineD3DSwapChain
*swapchain
;
6994 TRACE("Relaying to swapchain\n");
6996 if (IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
) == WINED3D_OK
) {
6997 IWineD3DSwapChain_GetGammaRamp(swapchain
, pRamp
);
6998 IWineD3DSwapChain_Release(swapchain
);
7004 /** ********************************************************
7005 * Notification functions
7006 ** ********************************************************/
7007 /** This function must be called in the release of a resource when ref == 0,
7008 * the contents of resource must still be correct,
7009 * any handles to other resource held by the caller must be closed
7010 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7011 *****************************************************/
7012 void device_resource_add(IWineD3DDeviceImpl
*This
, IWineD3DResource
*resource
)
7014 TRACE("(%p) : Adding resource %p\n", This
, resource
);
7016 list_add_head(&This
->resources
, &((IWineD3DResourceImpl
*) resource
)->resource
.resource_list_entry
);
7019 static void device_resource_remove(IWineD3DDeviceImpl
*This
, IWineD3DResource
*resource
)
7021 TRACE("(%p) : Removing resource %p\n", This
, resource
);
7023 list_remove(&((IWineD3DResourceImpl
*) resource
)->resource
.resource_list_entry
);
7026 void device_resource_released(IWineD3DDeviceImpl
*This
, IWineD3DResource
*resource
)
7028 WINED3DRESOURCETYPE type
= IWineD3DResource_GetType(resource
);
7031 TRACE("(%p) : resource %p\n", This
, resource
);
7033 context_resource_released((IWineD3DDevice
*)This
, resource
, type
);
7036 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7037 case WINED3DRTYPE_SURFACE
: {
7040 if (This
->d3d_initialized
)
7042 for (i
= 0; i
< This
->adapter
->gl_info
.limits
.buffers
; ++i
)
7044 if (This
->render_targets
[i
] == (IWineD3DSurface
*)resource
) {
7045 This
->render_targets
[i
] = NULL
;
7048 if (This
->stencilBufferTarget
== (IWineD3DSurface
*)resource
) {
7049 This
->stencilBufferTarget
= NULL
;
7055 case WINED3DRTYPE_TEXTURE
:
7056 case WINED3DRTYPE_CUBETEXTURE
:
7057 case WINED3DRTYPE_VOLUMETEXTURE
:
7058 for (counter
= 0; counter
< MAX_COMBINED_SAMPLERS
; counter
++) {
7059 if (This
->stateBlock
!= NULL
&& This
->stateBlock
->textures
[counter
] == (IWineD3DBaseTexture
*)resource
) {
7060 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter
, resource
);
7061 This
->stateBlock
->textures
[counter
] = NULL
;
7063 if (This
->updateStateBlock
!= This
->stateBlock
){
7064 if (This
->updateStateBlock
->textures
[counter
] == (IWineD3DBaseTexture
*)resource
) {
7065 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter
, resource
);
7066 This
->updateStateBlock
->textures
[counter
] = NULL
;
7071 case WINED3DRTYPE_VOLUME
:
7072 /* TODO: nothing really? */
7074 case WINED3DRTYPE_BUFFER
:
7077 TRACE("Cleaning up stream pointers\n");
7079 for(streamNumber
= 0; streamNumber
< MAX_STREAMS
; streamNumber
++){
7080 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7081 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7083 if (This
->updateStateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
7084 if ((IWineD3DResource
*)This
->updateStateBlock
->streamSource
[streamNumber
] == resource
) {
7085 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber
);
7086 This
->updateStateBlock
->streamSource
[streamNumber
] = 0;
7087 /* Set changed flag? */
7090 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) */
7091 if ((IWineD3DResource
*)This
->stateBlock
->streamSource
[streamNumber
] == resource
) {
7092 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber
);
7093 This
->stateBlock
->streamSource
[streamNumber
] = 0;
7098 if (This
->updateStateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
7099 if (This
->updateStateBlock
->pIndexData
== (IWineD3DBuffer
*)resource
) {
7100 This
->updateStateBlock
->pIndexData
= NULL
;
7103 if (This
->stateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
7104 if (This
->stateBlock
->pIndexData
== (IWineD3DBuffer
*)resource
) {
7105 This
->stateBlock
->pIndexData
= NULL
;
7112 FIXME("(%p) unknown resource type %p %u\n", This
, resource
, IWineD3DResource_GetType(resource
));
7117 /* Remove the resource from the resourceStore */
7118 device_resource_remove(This
, resource
);
7120 TRACE("Resource released\n");
7124 static HRESULT WINAPI
IWineD3DDeviceImpl_EnumResources(IWineD3DDevice
*iface
, D3DCB_ENUMRESOURCES pCallback
, void *pData
) {
7125 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7126 IWineD3DResourceImpl
*resource
, *cursor
;
7128 TRACE("(%p)->(%p,%p)\n", This
, pCallback
, pData
);
7130 LIST_FOR_EACH_ENTRY_SAFE(resource
, cursor
, &This
->resources
, IWineD3DResourceImpl
, resource
.resource_list_entry
) {
7131 TRACE("enumerating resource %p\n", resource
);
7132 IWineD3DResource_AddRef((IWineD3DResource
*) resource
);
7133 ret
= pCallback((IWineD3DResource
*) resource
, pData
);
7134 if(ret
== S_FALSE
) {
7135 TRACE("Canceling enumeration\n");
7142 /**********************************************************
7143 * IWineD3DDevice VTbl follows
7144 **********************************************************/
7146 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl
=
7148 /*** IUnknown methods ***/
7149 IWineD3DDeviceImpl_QueryInterface
,
7150 IWineD3DDeviceImpl_AddRef
,
7151 IWineD3DDeviceImpl_Release
,
7152 /*** IWineD3DDevice methods ***/
7153 IWineD3DDeviceImpl_GetParent
,
7154 /*** Creation methods**/
7155 IWineD3DDeviceImpl_CreateBuffer
,
7156 IWineD3DDeviceImpl_CreateVertexBuffer
,
7157 IWineD3DDeviceImpl_CreateIndexBuffer
,
7158 IWineD3DDeviceImpl_CreateStateBlock
,
7159 IWineD3DDeviceImpl_CreateSurface
,
7160 IWineD3DDeviceImpl_CreateRendertargetView
,
7161 IWineD3DDeviceImpl_CreateTexture
,
7162 IWineD3DDeviceImpl_CreateVolumeTexture
,
7163 IWineD3DDeviceImpl_CreateVolume
,
7164 IWineD3DDeviceImpl_CreateCubeTexture
,
7165 IWineD3DDeviceImpl_CreateQuery
,
7166 IWineD3DDeviceImpl_CreateSwapChain
,
7167 IWineD3DDeviceImpl_CreateVertexDeclaration
,
7168 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF
,
7169 IWineD3DDeviceImpl_CreateVertexShader
,
7170 IWineD3DDeviceImpl_CreatePixelShader
,
7171 IWineD3DDeviceImpl_CreatePalette
,
7172 /*** Odd functions **/
7173 IWineD3DDeviceImpl_Init3D
,
7174 IWineD3DDeviceImpl_InitGDI
,
7175 IWineD3DDeviceImpl_Uninit3D
,
7176 IWineD3DDeviceImpl_UninitGDI
,
7177 IWineD3DDeviceImpl_SetMultithreaded
,
7178 IWineD3DDeviceImpl_EvictManagedResources
,
7179 IWineD3DDeviceImpl_GetAvailableTextureMem
,
7180 IWineD3DDeviceImpl_GetBackBuffer
,
7181 IWineD3DDeviceImpl_GetCreationParameters
,
7182 IWineD3DDeviceImpl_GetDeviceCaps
,
7183 IWineD3DDeviceImpl_GetDirect3D
,
7184 IWineD3DDeviceImpl_GetDisplayMode
,
7185 IWineD3DDeviceImpl_SetDisplayMode
,
7186 IWineD3DDeviceImpl_GetNumberOfSwapChains
,
7187 IWineD3DDeviceImpl_GetRasterStatus
,
7188 IWineD3DDeviceImpl_GetSwapChain
,
7189 IWineD3DDeviceImpl_Reset
,
7190 IWineD3DDeviceImpl_SetDialogBoxMode
,
7191 IWineD3DDeviceImpl_SetCursorProperties
,
7192 IWineD3DDeviceImpl_SetCursorPosition
,
7193 IWineD3DDeviceImpl_ShowCursor
,
7194 /*** Getters and setters **/
7195 IWineD3DDeviceImpl_SetClipPlane
,
7196 IWineD3DDeviceImpl_GetClipPlane
,
7197 IWineD3DDeviceImpl_SetClipStatus
,
7198 IWineD3DDeviceImpl_GetClipStatus
,
7199 IWineD3DDeviceImpl_SetCurrentTexturePalette
,
7200 IWineD3DDeviceImpl_GetCurrentTexturePalette
,
7201 IWineD3DDeviceImpl_SetDepthStencilSurface
,
7202 IWineD3DDeviceImpl_GetDepthStencilSurface
,
7203 IWineD3DDeviceImpl_SetGammaRamp
,
7204 IWineD3DDeviceImpl_GetGammaRamp
,
7205 IWineD3DDeviceImpl_SetIndexBuffer
,
7206 IWineD3DDeviceImpl_GetIndexBuffer
,
7207 IWineD3DDeviceImpl_SetBaseVertexIndex
,
7208 IWineD3DDeviceImpl_GetBaseVertexIndex
,
7209 IWineD3DDeviceImpl_SetLight
,
7210 IWineD3DDeviceImpl_GetLight
,
7211 IWineD3DDeviceImpl_SetLightEnable
,
7212 IWineD3DDeviceImpl_GetLightEnable
,
7213 IWineD3DDeviceImpl_SetMaterial
,
7214 IWineD3DDeviceImpl_GetMaterial
,
7215 IWineD3DDeviceImpl_SetNPatchMode
,
7216 IWineD3DDeviceImpl_GetNPatchMode
,
7217 IWineD3DDeviceImpl_SetPaletteEntries
,
7218 IWineD3DDeviceImpl_GetPaletteEntries
,
7219 IWineD3DDeviceImpl_SetPixelShader
,
7220 IWineD3DDeviceImpl_GetPixelShader
,
7221 IWineD3DDeviceImpl_SetPixelShaderConstantB
,
7222 IWineD3DDeviceImpl_GetPixelShaderConstantB
,
7223 IWineD3DDeviceImpl_SetPixelShaderConstantI
,
7224 IWineD3DDeviceImpl_GetPixelShaderConstantI
,
7225 IWineD3DDeviceImpl_SetPixelShaderConstantF
,
7226 IWineD3DDeviceImpl_GetPixelShaderConstantF
,
7227 IWineD3DDeviceImpl_SetRenderState
,
7228 IWineD3DDeviceImpl_GetRenderState
,
7229 IWineD3DDeviceImpl_SetRenderTarget
,
7230 IWineD3DDeviceImpl_GetRenderTarget
,
7231 IWineD3DDeviceImpl_SetFrontBackBuffers
,
7232 IWineD3DDeviceImpl_SetSamplerState
,
7233 IWineD3DDeviceImpl_GetSamplerState
,
7234 IWineD3DDeviceImpl_SetScissorRect
,
7235 IWineD3DDeviceImpl_GetScissorRect
,
7236 IWineD3DDeviceImpl_SetSoftwareVertexProcessing
,
7237 IWineD3DDeviceImpl_GetSoftwareVertexProcessing
,
7238 IWineD3DDeviceImpl_SetStreamSource
,
7239 IWineD3DDeviceImpl_GetStreamSource
,
7240 IWineD3DDeviceImpl_SetStreamSourceFreq
,
7241 IWineD3DDeviceImpl_GetStreamSourceFreq
,
7242 IWineD3DDeviceImpl_SetTexture
,
7243 IWineD3DDeviceImpl_GetTexture
,
7244 IWineD3DDeviceImpl_SetTextureStageState
,
7245 IWineD3DDeviceImpl_GetTextureStageState
,
7246 IWineD3DDeviceImpl_SetTransform
,
7247 IWineD3DDeviceImpl_GetTransform
,
7248 IWineD3DDeviceImpl_SetVertexDeclaration
,
7249 IWineD3DDeviceImpl_GetVertexDeclaration
,
7250 IWineD3DDeviceImpl_SetVertexShader
,
7251 IWineD3DDeviceImpl_GetVertexShader
,
7252 IWineD3DDeviceImpl_SetVertexShaderConstantB
,
7253 IWineD3DDeviceImpl_GetVertexShaderConstantB
,
7254 IWineD3DDeviceImpl_SetVertexShaderConstantI
,
7255 IWineD3DDeviceImpl_GetVertexShaderConstantI
,
7256 IWineD3DDeviceImpl_SetVertexShaderConstantF
,
7257 IWineD3DDeviceImpl_GetVertexShaderConstantF
,
7258 IWineD3DDeviceImpl_SetViewport
,
7259 IWineD3DDeviceImpl_GetViewport
,
7260 IWineD3DDeviceImpl_MultiplyTransform
,
7261 IWineD3DDeviceImpl_ValidateDevice
,
7262 IWineD3DDeviceImpl_ProcessVertices
,
7263 /*** State block ***/
7264 IWineD3DDeviceImpl_BeginStateBlock
,
7265 IWineD3DDeviceImpl_EndStateBlock
,
7266 /*** Scene management ***/
7267 IWineD3DDeviceImpl_BeginScene
,
7268 IWineD3DDeviceImpl_EndScene
,
7269 IWineD3DDeviceImpl_Present
,
7270 IWineD3DDeviceImpl_Clear
,
7271 IWineD3DDeviceImpl_ClearRendertargetView
,
7273 IWineD3DDeviceImpl_SetPrimitiveType
,
7274 IWineD3DDeviceImpl_GetPrimitiveType
,
7275 IWineD3DDeviceImpl_DrawPrimitive
,
7276 IWineD3DDeviceImpl_DrawIndexedPrimitive
,
7277 IWineD3DDeviceImpl_DrawPrimitiveUP
,
7278 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP
,
7279 IWineD3DDeviceImpl_DrawPrimitiveStrided
,
7280 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided
,
7281 IWineD3DDeviceImpl_DrawRectPatch
,
7282 IWineD3DDeviceImpl_DrawTriPatch
,
7283 IWineD3DDeviceImpl_DeletePatch
,
7284 IWineD3DDeviceImpl_ColorFill
,
7285 IWineD3DDeviceImpl_UpdateTexture
,
7286 IWineD3DDeviceImpl_UpdateSurface
,
7287 IWineD3DDeviceImpl_GetFrontBufferData
,
7288 /*** object tracking ***/
7289 IWineD3DDeviceImpl_EnumResources
7292 HRESULT
device_init(IWineD3DDeviceImpl
*device
, IWineD3DImpl
*wined3d
,
7293 UINT adapter_idx
, WINED3DDEVTYPE device_type
, HWND focus_window
, DWORD flags
,
7294 IUnknown
*parent
, IWineD3DDeviceParent
*device_parent
)
7296 struct wined3d_adapter
*adapter
= &wined3d
->adapters
[adapter_idx
];
7297 const struct fragment_pipeline
*fragment_pipeline
;
7298 struct shader_caps shader_caps
;
7299 struct fragment_caps ffp_caps
;
7300 WINED3DDISPLAYMODE mode
;
7304 device
->lpVtbl
= &IWineD3DDevice_Vtbl
;
7306 device
->wined3d
= (IWineD3D
*)wined3d
;
7307 IWineD3D_AddRef(device
->wined3d
);
7308 device
->adapter
= wined3d
->adapter_count
? adapter
: NULL
;
7309 device
->parent
= parent
;
7310 device
->device_parent
= device_parent
;
7311 list_init(&device
->resources
);
7312 list_init(&device
->shaders
);
7314 device
->surface_alignment
= wined3d
->dxVersion
== 7 ? DDRAW_PITCH_ALIGNMENT
: D3D8_PITCH_ALIGNMENT
;
7315 device
->posFixup
[0] = 1.0f
; /* This is needed to get the x coord unmodified through a MAD. */
7317 /* Get the initial screen setup for ddraw. */
7318 hr
= IWineD3D_GetAdapterDisplayMode((IWineD3D
*)wined3d
, adapter_idx
, &mode
);
7321 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr
);
7322 IWineD3D_Release(device
->wined3d
);
7325 device
->ddraw_width
= mode
.Width
;
7326 device
->ddraw_height
= mode
.Height
;
7327 device
->ddraw_format
= mode
.Format
;
7329 /* Save the creation parameters. */
7330 device
->createParms
.AdapterOrdinal
= adapter_idx
;
7331 device
->createParms
.DeviceType
= device_type
;
7332 device
->createParms
.hFocusWindow
= focus_window
;
7333 device
->createParms
.BehaviorFlags
= flags
;
7335 device
->devType
= device_type
;
7336 for (i
= 0; i
< PATCHMAP_SIZE
; ++i
) list_init(&device
->patches
[i
]);
7338 select_shader_mode(&adapter
->gl_info
, &device
->ps_selected_mode
, &device
->vs_selected_mode
);
7339 device
->shader_backend
= select_shader_backend(adapter
, device_type
);
7341 memset(&shader_caps
, 0, sizeof(shader_caps
));
7342 device
->shader_backend
->shader_get_caps(device_type
, &adapter
->gl_info
, &shader_caps
);
7343 device
->d3d_vshader_constantF
= shader_caps
.MaxVertexShaderConst
;
7344 device
->d3d_pshader_constantF
= shader_caps
.MaxPixelShaderConst
;
7345 device
->vs_clipping
= shader_caps
.VSClipping
;
7347 memset(&ffp_caps
, 0, sizeof(ffp_caps
));
7348 fragment_pipeline
= select_fragment_implementation(adapter
, device_type
);
7349 device
->frag_pipe
= fragment_pipeline
;
7350 fragment_pipeline
->get_caps(device_type
, &adapter
->gl_info
, &ffp_caps
);
7351 device
->max_ffp_textures
= ffp_caps
.MaxSimultaneousTextures
;
7352 device
->max_ffp_texture_stages
= ffp_caps
.MaxTextureBlendStages
;
7354 hr
= compile_state_table(device
->StateTable
, device
->multistate_funcs
, &adapter
->gl_info
,
7355 ffp_vertexstate_template
, fragment_pipeline
, misc_state_template
);
7358 ERR("Failed to compile state table, hr %#x.\n", hr
);
7359 IWineD3D_Release(device
->wined3d
);
7363 device
->blitter
= select_blit_implementation(adapter
, device_type
);
7369 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl
*This
, DWORD state
) {
7370 DWORD rep
= This
->StateTable
[state
].representative
;
7371 struct wined3d_context
*context
;
7376 for(i
= 0; i
< This
->numContexts
; i
++) {
7377 context
= This
->contexts
[i
];
7378 if(isStateDirty(context
, rep
)) continue;
7380 context
->dirtyArray
[context
->numDirtyEntries
++] = rep
;
7383 context
->isStateDirty
[idx
] |= (1 << shift
);
7387 void get_drawable_size_pbuffer(struct wined3d_context
*context
, UINT
*width
, UINT
*height
)
7389 IWineD3DDeviceImpl
*device
= ((IWineD3DSurfaceImpl
*)context
->current_rt
)->resource
.wineD3DDevice
;
7390 /* The drawable size of a pbuffer render target is the current pbuffer size. */
7391 *width
= device
->pbufferWidth
;
7392 *height
= device
->pbufferHeight
;
7395 void get_drawable_size_fbo(struct wined3d_context
*context
, UINT
*width
, UINT
*height
)
7397 IWineD3DSurfaceImpl
*surface
= (IWineD3DSurfaceImpl
*)context
->current_rt
;
7398 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7399 *width
= surface
->pow2Width
;
7400 *height
= surface
->pow2Height
;
7403 void get_drawable_size_backbuffer(struct wined3d_context
*context
, UINT
*width
, UINT
*height
)
7405 IWineD3DSurfaceImpl
*surface
= (IWineD3DSurfaceImpl
*)context
->surface
;
7406 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7407 * current context's drawable, which is the size of the back buffer of the swapchain
7408 * the active context belongs to. The back buffer of the swapchain is stored as the
7409 * surface the context belongs to. */
7410 *width
= surface
->currentDesc
.Width
;
7411 *height
= surface
->currentDesc
.Height
;