2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
12 * Copyright 2009 Henri Verbeet for CodeWeavers
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
34 #include "wined3d_private.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(d3d
);
38 #define GLINFO_LOCATION This->adapter->gl_info
40 /* Define the default light parameters as specified by MSDN */
41 const WINED3DLIGHT WINED3D_default_light
= {
43 WINED3DLIGHT_DIRECTIONAL
, /* Type */
44 { 1.0f
, 1.0f
, 1.0f
, 0.0f
}, /* Diffuse r,g,b,a */
45 { 0.0f
, 0.0f
, 0.0f
, 0.0f
}, /* Specular r,g,b,a */
46 { 0.0f
, 0.0f
, 0.0f
, 0.0f
}, /* Ambient r,g,b,a, */
47 { 0.0f
, 0.0f
, 0.0f
}, /* Position x,y,z */
48 { 0.0f
, 0.0f
, 1.0f
}, /* Direction x,y,z */
51 0.0f
, 0.0f
, 0.0f
, /* Attenuation 0,1,2 */
56 #define IS_OPTION_TRUE(ch) ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
57 /**********************************************************
58 * Global variable / Constants follow
59 **********************************************************/
60 const float identity
[] =
62 1.0f
, 0.0f
, 0.0f
, 0.0f
,
63 0.0f
, 1.0f
, 0.0f
, 0.0f
,
64 0.0f
, 0.0f
, 1.0f
, 0.0f
,
65 0.0f
, 0.0f
, 0.0f
, 1.0f
,
66 }; /* When needed for comparisons */
68 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
69 * actually have the same values in GL and D3D. */
70 static GLenum
gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type
)
72 switch(primitive_type
)
74 case WINED3DPT_POINTLIST
:
77 case WINED3DPT_LINELIST
:
80 case WINED3DPT_LINESTRIP
:
83 case WINED3DPT_TRIANGLELIST
:
86 case WINED3DPT_TRIANGLESTRIP
:
87 return GL_TRIANGLE_STRIP
;
89 case WINED3DPT_TRIANGLEFAN
:
90 return GL_TRIANGLE_FAN
;
92 case WINED3DPT_LINELIST_ADJ
:
93 return GL_LINES_ADJACENCY_ARB
;
95 case WINED3DPT_LINESTRIP_ADJ
:
96 return GL_LINE_STRIP_ADJACENCY_ARB
;
98 case WINED3DPT_TRIANGLELIST_ADJ
:
99 return GL_TRIANGLES_ADJACENCY_ARB
;
101 case WINED3DPT_TRIANGLESTRIP_ADJ
:
102 return GL_TRIANGLE_STRIP_ADJACENCY_ARB
;
105 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type
));
110 static WINED3DPRIMITIVETYPE
d3d_primitive_type_from_gl(GLenum primitive_type
)
112 switch(primitive_type
)
115 return WINED3DPT_POINTLIST
;
118 return WINED3DPT_LINELIST
;
121 return WINED3DPT_LINESTRIP
;
124 return WINED3DPT_TRIANGLELIST
;
126 case GL_TRIANGLE_STRIP
:
127 return WINED3DPT_TRIANGLESTRIP
;
129 case GL_TRIANGLE_FAN
:
130 return WINED3DPT_TRIANGLEFAN
;
132 case GL_LINES_ADJACENCY_ARB
:
133 return WINED3DPT_LINELIST_ADJ
;
135 case GL_LINE_STRIP_ADJACENCY_ARB
:
136 return WINED3DPT_LINESTRIP_ADJ
;
138 case GL_TRIANGLES_ADJACENCY_ARB
:
139 return WINED3DPT_TRIANGLELIST_ADJ
;
141 case GL_TRIANGLE_STRIP_ADJACENCY_ARB
:
142 return WINED3DPT_TRIANGLESTRIP_ADJ
;
145 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type
));
146 return WINED3DPT_UNDEFINED
;
150 static BOOL
fixed_get_input(BYTE usage
, BYTE usage_idx
, unsigned int *regnum
)
152 if ((usage
== WINED3DDECLUSAGE_POSITION
|| usage
== WINED3DDECLUSAGE_POSITIONT
) && usage_idx
== 0)
153 *regnum
= WINED3D_FFP_POSITION
;
154 else if (usage
== WINED3DDECLUSAGE_BLENDWEIGHT
&& usage_idx
== 0)
155 *regnum
= WINED3D_FFP_BLENDWEIGHT
;
156 else if (usage
== WINED3DDECLUSAGE_BLENDINDICES
&& usage_idx
== 0)
157 *regnum
= WINED3D_FFP_BLENDINDICES
;
158 else if (usage
== WINED3DDECLUSAGE_NORMAL
&& usage_idx
== 0)
159 *regnum
= WINED3D_FFP_NORMAL
;
160 else if (usage
== WINED3DDECLUSAGE_PSIZE
&& usage_idx
== 0)
161 *regnum
= WINED3D_FFP_PSIZE
;
162 else if (usage
== WINED3DDECLUSAGE_COLOR
&& usage_idx
== 0)
163 *regnum
= WINED3D_FFP_DIFFUSE
;
164 else if (usage
== WINED3DDECLUSAGE_COLOR
&& usage_idx
== 1)
165 *regnum
= WINED3D_FFP_SPECULAR
;
166 else if (usage
== WINED3DDECLUSAGE_TEXCOORD
&& usage_idx
< WINED3DDP_MAXTEXCOORD
)
167 *regnum
= WINED3D_FFP_TEXCOORD0
+ usage_idx
;
170 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage
), usage_idx
);
178 /* Context activation is done by the caller. */
179 void device_stream_info_from_declaration(IWineD3DDeviceImpl
*This
,
180 BOOL use_vshader
, struct wined3d_stream_info
*stream_info
, BOOL
*fixup
)
182 /* We need to deal with frequency data! */
183 IWineD3DVertexDeclarationImpl
*declaration
= (IWineD3DVertexDeclarationImpl
*)This
->stateBlock
->vertexDecl
;
184 UINT stream_count
= This
->stateBlock
->streamIsUP
? 0 : declaration
->num_streams
;
185 const DWORD
*streams
= declaration
->streams
;
188 stream_info
->use_map
= 0;
189 stream_info
->swizzle_map
= 0;
191 /* Check for transformed vertices, disable vertex shader if present. */
192 stream_info
->position_transformed
= declaration
->position_transformed
;
193 if (declaration
->position_transformed
) use_vshader
= FALSE
;
195 /* Translate the declaration into strided data. */
196 for (i
= 0; i
< declaration
->element_count
; ++i
)
198 const struct wined3d_vertex_declaration_element
*element
= &declaration
->elements
[i
];
199 GLuint buffer_object
= 0;
200 const BYTE
*data
= NULL
;
205 TRACE("%p Element %p (%u of %u)\n", declaration
->elements
,
206 element
, i
+ 1, declaration
->element_count
);
208 if (!This
->stateBlock
->streamSource
[element
->input_slot
]) continue;
210 stride
= This
->stateBlock
->streamStride
[element
->input_slot
];
211 if (This
->stateBlock
->streamIsUP
)
213 TRACE("Stream %u is UP, %p\n", element
->input_slot
, This
->stateBlock
->streamSource
[element
->input_slot
]);
215 data
= (BYTE
*)This
->stateBlock
->streamSource
[element
->input_slot
];
219 TRACE("Stream %u isn't UP, %p\n", element
->input_slot
, This
->stateBlock
->streamSource
[element
->input_slot
]);
220 data
= buffer_get_memory(This
->stateBlock
->streamSource
[element
->input_slot
], 0, &buffer_object
);
222 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
223 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
224 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
225 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
226 * not, drawStridedSlow is needed, including a vertex buffer path. */
227 if (This
->stateBlock
->loadBaseVertexIndex
< 0)
229 WARN("loadBaseVertexIndex is < 0 (%d), not using vbos\n", This
->stateBlock
->loadBaseVertexIndex
);
231 data
= buffer_get_sysmem((struct wined3d_buffer
*)This
->stateBlock
->streamSource
[element
->input_slot
]);
232 if ((UINT_PTR
)data
< -This
->stateBlock
->loadBaseVertexIndex
* stride
)
234 FIXME("System memory vertex data load offset is negative!\n");
240 if (buffer_object
) *fixup
= TRUE
;
241 else if (*fixup
&& !use_vshader
242 && (element
->usage
== WINED3DDECLUSAGE_COLOR
243 || element
->usage
== WINED3DDECLUSAGE_POSITIONT
))
245 static BOOL warned
= FALSE
;
248 /* This may be bad with the fixed function pipeline. */
249 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
255 data
+= element
->offset
;
257 TRACE("offset %u input_slot %u usage_idx %d\n", element
->offset
, element
->input_slot
, element
->usage_idx
);
261 if (element
->output_slot
== ~0U)
263 /* TODO: Assuming vertexdeclarations are usually used with the
264 * same or a similar shader, it might be worth it to store the
265 * last used output slot and try that one first. */
266 stride_used
= vshader_get_input(This
->stateBlock
->vertexShader
,
267 element
->usage
, element
->usage_idx
, &idx
);
271 idx
= element
->output_slot
;
277 if (!element
->ffp_valid
)
279 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
280 debug_d3dformat(element
->format_desc
->format
), debug_d3ddeclusage(element
->usage
));
285 stride_used
= fixed_get_input(element
->usage
, element
->usage_idx
, &idx
);
291 TRACE("Load %s array %u [usage %s, usage_idx %u, "
292 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
293 use_vshader
? "shader": "fixed function", idx
,
294 debug_d3ddeclusage(element
->usage
), element
->usage_idx
, element
->input_slot
,
295 element
->offset
, stride
, debug_d3dformat(element
->format_desc
->format
), buffer_object
);
297 stream_info
->elements
[idx
].format_desc
= element
->format_desc
;
298 stream_info
->elements
[idx
].stride
= stride
;
299 stream_info
->elements
[idx
].data
= data
;
300 stream_info
->elements
[idx
].stream_idx
= element
->input_slot
;
301 stream_info
->elements
[idx
].buffer_object
= buffer_object
;
303 if (!This
->adapter
->gl_info
.supported
[EXT_VERTEX_ARRAY_BGRA
]
304 && element
->format_desc
->format
== WINED3DFMT_B8G8R8A8_UNORM
)
306 stream_info
->swizzle_map
|= 1 << idx
;
308 stream_info
->use_map
|= 1 << idx
;
312 /* Now call PreLoad on all the vertex buffers. In the very rare case
313 * that the buffers stopps converting PreLoad will dirtify the VDECL again.
314 * The vertex buffer can now use the strided structure in the device instead of finding its
317 * NULL streams won't be recorded in the array, UP streams won't be either. A stream is only
319 for (i
= 0; i
< stream_count
; ++i
)
321 IWineD3DBuffer
*vb
= This
->stateBlock
->streamSource
[streams
[i
]];
322 if (vb
) IWineD3DBuffer_PreLoad(vb
);
326 static void stream_info_element_from_strided(const struct wined3d_gl_info
*gl_info
,
327 const struct WineDirect3DStridedData
*strided
, struct wined3d_stream_info_element
*e
)
329 const struct GlPixelFormatDesc
*format_desc
= getFormatDescEntry(strided
->format
, gl_info
);
330 e
->format_desc
= format_desc
;
331 e
->stride
= strided
->dwStride
;
332 e
->data
= strided
->lpData
;
334 e
->buffer_object
= 0;
337 void device_stream_info_from_strided(const struct wined3d_gl_info
*gl_info
,
338 const struct WineDirect3DVertexStridedData
*strided
, struct wined3d_stream_info
*stream_info
)
342 memset(stream_info
, 0, sizeof(*stream_info
));
344 if (strided
->position
.lpData
)
345 stream_info_element_from_strided(gl_info
, &strided
->position
, &stream_info
->elements
[WINED3D_FFP_POSITION
]);
346 if (strided
->normal
.lpData
)
347 stream_info_element_from_strided(gl_info
, &strided
->normal
, &stream_info
->elements
[WINED3D_FFP_NORMAL
]);
348 if (strided
->diffuse
.lpData
)
349 stream_info_element_from_strided(gl_info
, &strided
->diffuse
, &stream_info
->elements
[WINED3D_FFP_DIFFUSE
]);
350 if (strided
->specular
.lpData
)
351 stream_info_element_from_strided(gl_info
, &strided
->specular
, &stream_info
->elements
[WINED3D_FFP_SPECULAR
]);
353 for (i
= 0; i
< WINED3DDP_MAXTEXCOORD
; ++i
)
355 if (strided
->texCoords
[i
].lpData
)
356 stream_info_element_from_strided(gl_info
, &strided
->texCoords
[i
],
357 &stream_info
->elements
[WINED3D_FFP_TEXCOORD0
+ i
]);
360 stream_info
->position_transformed
= strided
->position_transformed
;
362 for (i
= 0; i
< sizeof(stream_info
->elements
) / sizeof(*stream_info
->elements
); ++i
)
364 if (!stream_info
->elements
[i
].format_desc
) continue;
366 if (!gl_info
->supported
[EXT_VERTEX_ARRAY_BGRA
]
367 && stream_info
->elements
[i
].format_desc
->format
== WINED3DFMT_B8G8R8A8_UNORM
)
369 stream_info
->swizzle_map
|= 1 << i
;
371 stream_info
->use_map
|= 1 << i
;
375 /**********************************************************
376 * IUnknown parts follows
377 **********************************************************/
379 static HRESULT WINAPI
IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice
*iface
,REFIID riid
,LPVOID
*ppobj
)
381 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
383 TRACE("(%p)->(%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
384 if (IsEqualGUID(riid
, &IID_IUnknown
)
385 || IsEqualGUID(riid
, &IID_IWineD3DBase
)
386 || IsEqualGUID(riid
, &IID_IWineD3DDevice
)) {
387 IUnknown_AddRef(iface
);
392 return E_NOINTERFACE
;
395 static ULONG WINAPI
IWineD3DDeviceImpl_AddRef(IWineD3DDevice
*iface
) {
396 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
397 ULONG refCount
= InterlockedIncrement(&This
->ref
);
399 TRACE("(%p) : AddRef increasing from %d\n", This
, refCount
- 1);
403 static ULONG WINAPI
IWineD3DDeviceImpl_Release(IWineD3DDevice
*iface
) {
404 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
405 ULONG refCount
= InterlockedDecrement(&This
->ref
);
407 TRACE("(%p) : Releasing from %d\n", This
, refCount
+ 1);
412 for (i
= 0; i
< sizeof(This
->multistate_funcs
)/sizeof(This
->multistate_funcs
[0]); ++i
) {
413 HeapFree(GetProcessHeap(), 0, This
->multistate_funcs
[i
]);
414 This
->multistate_funcs
[i
] = NULL
;
417 /* TODO: Clean up all the surfaces and textures! */
418 /* NOTE: You must release the parent if the object was created via a callback
419 ** ***************************/
421 if (!list_empty(&This
->resources
)) {
422 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This
);
423 dumpResources(&This
->resources
);
426 if(This
->contexts
) ERR("Context array not freed!\n");
427 if (This
->hardwareCursor
) DestroyCursor(This
->hardwareCursor
);
428 This
->haveHardwareCursor
= FALSE
;
430 IWineD3D_Release(This
->wined3d
);
431 This
->wined3d
= NULL
;
432 HeapFree(GetProcessHeap(), 0, This
);
433 TRACE("Freed device %p\n", This
);
439 /**********************************************************
440 * IWineD3DDevice implementation follows
441 **********************************************************/
442 static HRESULT WINAPI
IWineD3DDeviceImpl_GetParent(IWineD3DDevice
*iface
, IUnknown
**pParent
) {
443 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
444 *pParent
= This
->parent
;
445 IUnknown_AddRef(This
->parent
);
449 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice
*iface
, struct wined3d_buffer_desc
*desc
,
450 const void *data
, IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
, IWineD3DBuffer
**buffer
)
452 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
453 struct wined3d_buffer
*object
;
456 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface
, desc
, data
, parent
, buffer
);
458 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
461 ERR("Failed to allocate memory\n");
462 return E_OUTOFMEMORY
;
465 FIXME("Ignoring access flags (pool)\n");
467 hr
= buffer_init(object
, This
, desc
->byte_width
, desc
->usage
, WINED3DFMT_UNKNOWN
,
468 WINED3DPOOL_MANAGED
, GL_ARRAY_BUFFER_ARB
, data
, parent
, parent_ops
);
471 WARN("Failed to initialize buffer, hr %#x.\n", hr
);
472 HeapFree(GetProcessHeap(), 0, object
);
475 object
->desc
= *desc
;
477 TRACE("Created buffer %p.\n", object
);
479 *buffer
= (IWineD3DBuffer
*)object
;
484 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice
*iface
, UINT Size
,
485 DWORD Usage
, DWORD FVF
, WINED3DPOOL Pool
, IWineD3DBuffer
**ppVertexBuffer
,
486 IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
)
488 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
489 struct wined3d_buffer
*object
;
493 if (Pool
== WINED3DPOOL_SCRATCH
)
495 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
496 * anyway, SCRATCH vertex buffers aren't usable anywhere
498 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
499 *ppVertexBuffer
= NULL
;
500 return WINED3DERR_INVALIDCALL
;
503 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
506 ERR("Out of memory\n");
507 *ppVertexBuffer
= NULL
;
508 return WINED3DERR_OUTOFVIDEOMEMORY
;
511 hr
= buffer_init(object
, This
, Size
, Usage
, WINED3DFMT_VERTEXDATA
,
512 Pool
, GL_ARRAY_BUFFER_ARB
, NULL
, parent
, parent_ops
);
515 WARN("Failed to initialize buffer, hr %#x.\n", hr
);
516 HeapFree(GetProcessHeap(), 0, object
);
520 TRACE("Created buffer %p.\n", object
);
521 TRACE("FVF %#x, Pool %#x.\n", FVF
, Pool
);
522 *ppVertexBuffer
= (IWineD3DBuffer
*)object
;
524 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
525 * drawStridedFast (half-life 2).
527 * Basically converting the vertices in the buffer is quite expensive, and observations
528 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
529 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
531 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
532 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
533 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
534 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
536 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
537 * more. In this call we can convert dx7 buffers too.
539 conv
= ((FVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) || (FVF
& (WINED3DFVF_DIFFUSE
| WINED3DFVF_SPECULAR
));
540 if (!This
->adapter
->gl_info
.supported
[ARB_VERTEX_BUFFER_OBJECT
])
542 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
543 } else if(Pool
== WINED3DPOOL_SYSTEMMEM
) {
544 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
545 } else if(Usage
& WINED3DUSAGE_DYNAMIC
) {
546 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
547 } else if(!(Usage
& WINED3DUSAGE_OPTIMIZE
) && conv
) {
548 TRACE("Not creating a vbo because the fvf needs conversion, but VB optimization is disabled\n");
550 object
->flags
|= WINED3D_BUFFER_CREATEBO
;
555 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice
*iface
,
556 UINT Length
, DWORD Usage
, WINED3DPOOL Pool
, IWineD3DBuffer
**ppIndexBuffer
,
557 IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
)
559 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
560 struct wined3d_buffer
*object
;
563 TRACE("(%p) Creating index buffer\n", This
);
565 /* Allocate the storage for the device */
566 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
569 ERR("Out of memory\n");
570 *ppIndexBuffer
= NULL
;
571 return WINED3DERR_OUTOFVIDEOMEMORY
;
574 hr
= buffer_init(object
, This
, Length
, Usage
| WINED3DUSAGE_STATICDECL
,
575 WINED3DFMT_UNKNOWN
, Pool
, GL_ELEMENT_ARRAY_BUFFER_ARB
, NULL
, parent
, parent_ops
);
578 WARN("Failed to initialize buffer, hr %#x\n", hr
);
579 HeapFree(GetProcessHeap(), 0, object
);
583 TRACE("Created buffer %p.\n", object
);
585 if (Pool
!= WINED3DPOOL_SYSTEMMEM
&& !(Usage
& WINED3DUSAGE_DYNAMIC
)
586 && This
->adapter
->gl_info
.supported
[ARB_VERTEX_BUFFER_OBJECT
])
588 object
->flags
|= WINED3D_BUFFER_CREATEBO
;
591 *ppIndexBuffer
= (IWineD3DBuffer
*) object
;
596 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice
*iface
,
597 WINED3DSTATEBLOCKTYPE type
, IWineD3DStateBlock
**stateblock
, IUnknown
*parent
)
599 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
600 IWineD3DStateBlockImpl
*object
;
603 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
606 ERR("Failed to allocate stateblock memory.\n");
607 return E_OUTOFMEMORY
;
610 hr
= stateblock_init(object
, This
, type
);
613 WARN("Failed to initialize stateblock, hr %#x.\n", hr
);
614 HeapFree(GetProcessHeap(), 0, object
);
618 TRACE("Created stateblock %p.\n", object
);
619 *stateblock
= (IWineD3DStateBlock
*)object
;
624 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice
*iface
, UINT Width
, UINT Height
,
625 WINED3DFORMAT Format
, BOOL Lockable
, BOOL Discard
, UINT Level
, IWineD3DSurface
**ppSurface
,
626 DWORD Usage
, WINED3DPOOL Pool
, WINED3DMULTISAMPLE_TYPE MultiSample
, DWORD MultisampleQuality
,
627 WINED3DSURFTYPE Impl
, IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
)
629 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
630 IWineD3DSurfaceImpl
*object
;
633 TRACE("(%p) Create surface\n",This
);
635 if (Impl
== SURFACE_OPENGL
&& !This
->adapter
)
637 ERR("OpenGL surfaces are not available without OpenGL.\n");
638 return WINED3DERR_NOTAVAILABLE
;
641 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
644 ERR("Failed to allocate surface memory.\n");
646 return WINED3DERR_OUTOFVIDEOMEMORY
;
649 hr
= surface_init(object
, Impl
, This
->surface_alignment
, Width
, Height
, Level
, Lockable
,
650 Discard
, MultiSample
, MultisampleQuality
, This
, Usage
, Format
, Pool
, parent
, parent_ops
);
653 WARN("Failed to initialize surface, returning %#x.\n", hr
);
654 HeapFree(GetProcessHeap(), 0, object
);
659 TRACE("(%p) : Created surface %p\n", This
, object
);
661 *ppSurface
= (IWineD3DSurface
*)object
;
666 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice
*iface
,
667 IWineD3DResource
*resource
, IUnknown
*parent
, IWineD3DRendertargetView
**rendertarget_view
)
669 struct wined3d_rendertarget_view
*object
;
671 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
674 ERR("Failed to allocate memory\n");
675 return E_OUTOFMEMORY
;
678 object
->vtbl
= &wined3d_rendertarget_view_vtbl
;
679 object
->refcount
= 1;
680 IWineD3DResource_AddRef(resource
);
681 object
->resource
= resource
;
682 object
->parent
= parent
;
684 *rendertarget_view
= (IWineD3DRendertargetView
*)object
;
689 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice
*iface
,
690 UINT Width
, UINT Height
, UINT Levels
, DWORD Usage
, WINED3DFORMAT Format
, WINED3DPOOL Pool
,
691 IWineD3DTexture
**ppTexture
, IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
)
693 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
694 IWineD3DTextureImpl
*object
;
697 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This
, Width
, Height
, Levels
, Usage
);
698 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
699 Format
, debug_d3dformat(Format
), Pool
, ppTexture
, parent
);
701 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
704 ERR("Out of memory\n");
706 return WINED3DERR_OUTOFVIDEOMEMORY
;
709 hr
= texture_init(object
, Width
, Height
, Levels
, This
, Usage
, Format
, Pool
, parent
, parent_ops
);
712 WARN("Failed to initialize texture, returning %#x\n", hr
);
713 HeapFree(GetProcessHeap(), 0, object
);
718 *ppTexture
= (IWineD3DTexture
*)object
;
720 TRACE("(%p) : Created texture %p\n", This
, object
);
725 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice
*iface
,
726 UINT Width
, UINT Height
, UINT Depth
, UINT Levels
, DWORD Usage
, WINED3DFORMAT Format
, WINED3DPOOL Pool
,
727 IWineD3DVolumeTexture
**ppVolumeTexture
, IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
)
729 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
730 IWineD3DVolumeTextureImpl
*object
;
733 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
734 Depth
, Levels
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
736 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
739 ERR("Out of memory\n");
740 *ppVolumeTexture
= NULL
;
741 return WINED3DERR_OUTOFVIDEOMEMORY
;
744 hr
= volumetexture_init(object
, Width
, Height
, Depth
, Levels
, This
, Usage
, Format
, Pool
, parent
, parent_ops
);
747 WARN("Failed to initialize volumetexture, returning %#x\n", hr
);
748 HeapFree(GetProcessHeap(), 0, object
);
749 *ppVolumeTexture
= NULL
;
753 TRACE("(%p) : Created volume texture %p.\n", This
, object
);
754 *ppVolumeTexture
= (IWineD3DVolumeTexture
*)object
;
759 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice
*iface
, UINT Width
, UINT Height
,
760 UINT Depth
, DWORD Usage
, WINED3DFORMAT Format
, WINED3DPOOL Pool
, IWineD3DVolume
**ppVolume
,
761 IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
)
763 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
764 IWineD3DVolumeImpl
*object
;
767 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
768 Depth
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
770 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
773 ERR("Out of memory\n");
775 return WINED3DERR_OUTOFVIDEOMEMORY
;
778 hr
= volume_init(object
, This
, Width
, Height
, Depth
, Usage
, Format
, Pool
, parent
, parent_ops
);
781 WARN("Failed to initialize volume, returning %#x.\n", hr
);
782 HeapFree(GetProcessHeap(), 0, object
);
786 TRACE("(%p) : Created volume %p.\n", This
, object
);
787 *ppVolume
= (IWineD3DVolume
*)object
;
792 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice
*iface
, UINT EdgeLength
, UINT Levels
,
793 DWORD Usage
, WINED3DFORMAT Format
, WINED3DPOOL Pool
, IWineD3DCubeTexture
**ppCubeTexture
,
794 IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
)
796 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
797 IWineD3DCubeTextureImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
800 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
803 ERR("Out of memory\n");
804 *ppCubeTexture
= NULL
;
805 return WINED3DERR_OUTOFVIDEOMEMORY
;
808 hr
= cubetexture_init(object
, EdgeLength
, Levels
, This
, Usage
, Format
, Pool
, parent
, parent_ops
);
811 WARN("Failed to initialize cubetexture, returning %#x\n", hr
);
812 HeapFree(GetProcessHeap(), 0, object
);
813 *ppCubeTexture
= NULL
;
817 TRACE("(%p) : Created Cube Texture %p\n", This
, object
);
818 *ppCubeTexture
= (IWineD3DCubeTexture
*)object
;
823 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice
*iface
, WINED3DQUERYTYPE Type
, IWineD3DQuery
**ppQuery
, IUnknown
* parent
) {
824 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
825 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
826 IWineD3DQueryImpl
*object
; /*NOTE: impl ref allowed since this is a create function */
827 HRESULT hr
= WINED3DERR_NOTAVAILABLE
;
828 const IWineD3DQueryVtbl
*vtable
;
830 /* Just a check to see if we support this type of query */
832 case WINED3DQUERYTYPE_OCCLUSION
:
833 TRACE("(%p) occlusion query\n", This
);
834 if (gl_info
->supported
[ARB_OCCLUSION_QUERY
])
837 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
839 vtable
= &IWineD3DOcclusionQuery_Vtbl
;
842 case WINED3DQUERYTYPE_EVENT
:
843 if (!gl_info
->supported
[NV_FENCE
] && !gl_info
->supported
[APPLE_FENCE
])
845 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
846 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
848 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This
);
850 vtable
= &IWineD3DEventQuery_Vtbl
;
854 case WINED3DQUERYTYPE_VCACHE
:
855 case WINED3DQUERYTYPE_RESOURCEMANAGER
:
856 case WINED3DQUERYTYPE_VERTEXSTATS
:
857 case WINED3DQUERYTYPE_TIMESTAMP
:
858 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT
:
859 case WINED3DQUERYTYPE_TIMESTAMPFREQ
:
860 case WINED3DQUERYTYPE_PIPELINETIMINGS
:
861 case WINED3DQUERYTYPE_INTERFACETIMINGS
:
862 case WINED3DQUERYTYPE_VERTEXTIMINGS
:
863 case WINED3DQUERYTYPE_PIXELTIMINGS
:
864 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS
:
865 case WINED3DQUERYTYPE_CACHEUTILIZATION
:
867 /* Use the base Query vtable until we have a special one for each query */
868 vtable
= &IWineD3DQuery_Vtbl
;
869 FIXME("(%p) Unhandled query type %d\n", This
, Type
);
871 if(NULL
== ppQuery
|| hr
!= WINED3D_OK
) {
875 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
878 ERR("Out of memory\n");
880 return WINED3DERR_OUTOFVIDEOMEMORY
;
883 object
->lpVtbl
= vtable
;
885 object
->state
= QUERY_CREATED
;
886 object
->device
= This
;
887 object
->parent
= parent
;
890 *ppQuery
= (IWineD3DQuery
*)object
;
892 /* allocated the 'extended' data based on the type of query requested */
894 case WINED3DQUERYTYPE_OCCLUSION
:
895 object
->extendedData
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_occlusion_query
));
896 ((struct wined3d_occlusion_query
*)object
->extendedData
)->context
= NULL
;
899 case WINED3DQUERYTYPE_EVENT
:
900 object
->extendedData
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_event_query
));
901 ((struct wined3d_event_query
*)object
->extendedData
)->context
= NULL
;
904 case WINED3DQUERYTYPE_VCACHE
:
905 case WINED3DQUERYTYPE_RESOURCEMANAGER
:
906 case WINED3DQUERYTYPE_VERTEXSTATS
:
907 case WINED3DQUERYTYPE_TIMESTAMP
:
908 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT
:
909 case WINED3DQUERYTYPE_TIMESTAMPFREQ
:
910 case WINED3DQUERYTYPE_PIPELINETIMINGS
:
911 case WINED3DQUERYTYPE_INTERFACETIMINGS
:
912 case WINED3DQUERYTYPE_VERTEXTIMINGS
:
913 case WINED3DQUERYTYPE_PIXELTIMINGS
:
914 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS
:
915 case WINED3DQUERYTYPE_CACHEUTILIZATION
:
917 object
->extendedData
= 0;
918 FIXME("(%p) Unhandled query type %d\n",This
, Type
);
920 TRACE("(%p) : Created Query %p\n", This
, object
);
924 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice
*iface
,
925 WINED3DPRESENT_PARAMETERS
*present_parameters
, IWineD3DSwapChain
**swapchain
,
926 IUnknown
*parent
, WINED3DSURFTYPE surface_type
)
928 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
929 IWineD3DSwapChainImpl
*object
;
932 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
933 iface
, present_parameters
, swapchain
, parent
, surface_type
);
935 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
938 ERR("Failed to allocate swapchain memory.\n");
939 return E_OUTOFMEMORY
;
942 hr
= swapchain_init(object
, surface_type
, This
, present_parameters
, parent
);
945 WARN("Failed to initialize swapchain, hr %#x.\n", hr
);
946 HeapFree(GetProcessHeap(), 0, object
);
950 TRACE("Created swapchain %p.\n", object
);
951 *swapchain
= (IWineD3DSwapChain
*)object
;
956 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
957 static UINT WINAPI
IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice
*iface
) {
958 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
959 TRACE("(%p)\n", This
);
961 return This
->NumberOfSwapChains
;
964 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice
*iface
, UINT iSwapChain
, IWineD3DSwapChain
**pSwapChain
) {
965 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
966 TRACE("(%p) : swapchain %d\n", This
, iSwapChain
);
968 if(iSwapChain
< This
->NumberOfSwapChains
) {
969 *pSwapChain
= This
->swapchains
[iSwapChain
];
970 IWineD3DSwapChain_AddRef(*pSwapChain
);
971 TRACE("(%p) returning %p\n", This
, *pSwapChain
);
974 TRACE("Swapchain out of range\n");
976 return WINED3DERR_INVALIDCALL
;
980 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice
*iface
,
981 IWineD3DVertexDeclaration
**declaration
, IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
,
982 const WINED3DVERTEXELEMENT
*elements
, UINT element_count
)
984 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
985 IWineD3DVertexDeclarationImpl
*object
= NULL
;
988 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
989 iface
, declaration
, parent
, elements
, element_count
);
991 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
994 ERR("Failed to allocate vertex declaration memory.\n");
995 return E_OUTOFMEMORY
;
998 hr
= vertexdeclaration_init(object
, This
, elements
, element_count
, parent
, parent_ops
);
1001 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr
);
1002 HeapFree(GetProcessHeap(), 0, object
);
1006 TRACE("Created vertex declaration %p.\n", object
);
1007 *declaration
= (IWineD3DVertexDeclaration
*)object
;
1012 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl
*This
, /* For the GL info, which has the type table */
1013 DWORD fvf
, WINED3DVERTEXELEMENT
** ppVertexElements
) {
1015 unsigned int idx
, idx2
;
1016 unsigned int offset
;
1017 BOOL has_pos
= (fvf
& WINED3DFVF_POSITION_MASK
) != 0;
1018 BOOL has_blend
= (fvf
& WINED3DFVF_XYZB5
) > WINED3DFVF_XYZRHW
;
1019 BOOL has_blend_idx
= has_blend
&&
1020 (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB5
) ||
1021 (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
) ||
1022 (fvf
& WINED3DFVF_LASTBETA_UBYTE4
));
1023 BOOL has_normal
= (fvf
& WINED3DFVF_NORMAL
) != 0;
1024 BOOL has_psize
= (fvf
& WINED3DFVF_PSIZE
) != 0;
1025 BOOL has_diffuse
= (fvf
& WINED3DFVF_DIFFUSE
) != 0;
1026 BOOL has_specular
= (fvf
& WINED3DFVF_SPECULAR
) !=0;
1028 DWORD num_textures
= (fvf
& WINED3DFVF_TEXCOUNT_MASK
) >> WINED3DFVF_TEXCOUNT_SHIFT
;
1029 DWORD texcoords
= (fvf
& 0xFFFF0000) >> 16;
1030 WINED3DVERTEXELEMENT
*elements
= NULL
;
1033 DWORD num_blends
= 1 + (((fvf
& WINED3DFVF_XYZB5
) - WINED3DFVF_XYZB1
) >> 1);
1034 if (has_blend_idx
) num_blends
--;
1036 /* Compute declaration size */
1037 size
= has_pos
+ (has_blend
&& num_blends
> 0) + has_blend_idx
+ has_normal
+
1038 has_psize
+ has_diffuse
+ has_specular
+ num_textures
;
1040 /* convert the declaration */
1041 elements
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WINED3DVERTEXELEMENT
));
1042 if (!elements
) return ~0U;
1046 if (!has_blend
&& (fvf
& WINED3DFVF_XYZRHW
)) {
1047 elements
[idx
].format
= WINED3DFMT_R32G32B32A32_FLOAT
;
1048 elements
[idx
].usage
= WINED3DDECLUSAGE_POSITIONT
;
1050 else if ((fvf
& WINED3DFVF_XYZW
) == WINED3DFVF_XYZW
) {
1051 elements
[idx
].format
= WINED3DFMT_R32G32B32A32_FLOAT
;
1052 elements
[idx
].usage
= WINED3DDECLUSAGE_POSITION
;
1055 elements
[idx
].format
= WINED3DFMT_R32G32B32_FLOAT
;
1056 elements
[idx
].usage
= WINED3DDECLUSAGE_POSITION
;
1058 elements
[idx
].usage_idx
= 0;
1061 if (has_blend
&& (num_blends
> 0)) {
1062 if (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB2
) && (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
))
1063 elements
[idx
].format
= WINED3DFMT_B8G8R8A8_UNORM
;
1065 switch(num_blends
) {
1066 case 1: elements
[idx
].format
= WINED3DFMT_R32_FLOAT
; break;
1067 case 2: elements
[idx
].format
= WINED3DFMT_R32G32_FLOAT
; break;
1068 case 3: elements
[idx
].format
= WINED3DFMT_R32G32B32_FLOAT
; break;
1069 case 4: elements
[idx
].format
= WINED3DFMT_R32G32B32A32_FLOAT
; break;
1071 ERR("Unexpected amount of blend values: %u\n", num_blends
);
1074 elements
[idx
].usage
= WINED3DDECLUSAGE_BLENDWEIGHT
;
1075 elements
[idx
].usage_idx
= 0;
1078 if (has_blend_idx
) {
1079 if (fvf
& WINED3DFVF_LASTBETA_UBYTE4
||
1080 (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB2
) && (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
)))
1081 elements
[idx
].format
= WINED3DFMT_R8G8B8A8_UINT
;
1082 else if (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
)
1083 elements
[idx
].format
= WINED3DFMT_B8G8R8A8_UNORM
;
1085 elements
[idx
].format
= WINED3DFMT_R32_FLOAT
;
1086 elements
[idx
].usage
= WINED3DDECLUSAGE_BLENDINDICES
;
1087 elements
[idx
].usage_idx
= 0;
1091 elements
[idx
].format
= WINED3DFMT_R32G32B32_FLOAT
;
1092 elements
[idx
].usage
= WINED3DDECLUSAGE_NORMAL
;
1093 elements
[idx
].usage_idx
= 0;
1097 elements
[idx
].format
= WINED3DFMT_R32_FLOAT
;
1098 elements
[idx
].usage
= WINED3DDECLUSAGE_PSIZE
;
1099 elements
[idx
].usage_idx
= 0;
1103 elements
[idx
].format
= WINED3DFMT_B8G8R8A8_UNORM
;
1104 elements
[idx
].usage
= WINED3DDECLUSAGE_COLOR
;
1105 elements
[idx
].usage_idx
= 0;
1109 elements
[idx
].format
= WINED3DFMT_B8G8R8A8_UNORM
;
1110 elements
[idx
].usage
= WINED3DDECLUSAGE_COLOR
;
1111 elements
[idx
].usage_idx
= 1;
1114 for (idx2
= 0; idx2
< num_textures
; idx2
++) {
1115 unsigned int numcoords
= (texcoords
>> (idx2
*2)) & 0x03;
1116 switch (numcoords
) {
1117 case WINED3DFVF_TEXTUREFORMAT1
:
1118 elements
[idx
].format
= WINED3DFMT_R32_FLOAT
;
1120 case WINED3DFVF_TEXTUREFORMAT2
:
1121 elements
[idx
].format
= WINED3DFMT_R32G32_FLOAT
;
1123 case WINED3DFVF_TEXTUREFORMAT3
:
1124 elements
[idx
].format
= WINED3DFMT_R32G32B32_FLOAT
;
1126 case WINED3DFVF_TEXTUREFORMAT4
:
1127 elements
[idx
].format
= WINED3DFMT_R32G32B32A32_FLOAT
;
1130 elements
[idx
].usage
= WINED3DDECLUSAGE_TEXCOORD
;
1131 elements
[idx
].usage_idx
= idx2
;
1135 /* Now compute offsets, and initialize the rest of the fields */
1136 for (idx
= 0, offset
= 0; idx
< size
; ++idx
)
1138 const struct GlPixelFormatDesc
*format_desc
= getFormatDescEntry(elements
[idx
].format
, &This
->adapter
->gl_info
);
1139 elements
[idx
].input_slot
= 0;
1140 elements
[idx
].method
= WINED3DDECLMETHOD_DEFAULT
;
1141 elements
[idx
].offset
= offset
;
1142 offset
+= format_desc
->component_count
* format_desc
->component_size
;
1145 *ppVertexElements
= elements
;
1149 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice
*iface
,
1150 IWineD3DVertexDeclaration
**declaration
, IUnknown
*parent
,
1151 const struct wined3d_parent_ops
*parent_ops
, DWORD fvf
)
1153 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1154 WINED3DVERTEXELEMENT
*elements
;
1158 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface
, declaration
, parent
, fvf
);
1160 size
= ConvertFvfToDeclaration(This
, fvf
, &elements
);
1161 if (size
== ~0U) return E_OUTOFMEMORY
;
1163 hr
= IWineD3DDevice_CreateVertexDeclaration(iface
, declaration
, parent
, parent_ops
, elements
, size
);
1164 HeapFree(GetProcessHeap(), 0, elements
);
1168 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice
*iface
,
1169 const DWORD
*pFunction
, const struct wined3d_shader_signature
*output_signature
,
1170 IWineD3DVertexShader
**ppVertexShader
, IUnknown
*parent
,
1171 const struct wined3d_parent_ops
*parent_ops
)
1173 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1174 IWineD3DVertexShaderImpl
*object
;
1177 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1180 ERR("Failed to allocate shader memory.\n");
1181 return E_OUTOFMEMORY
;
1184 hr
= vertexshader_init(object
, This
, pFunction
, output_signature
, parent
, parent_ops
);
1187 WARN("Failed to initialize vertex shader, hr %#x.\n", hr
);
1188 HeapFree(GetProcessHeap(), 0, object
);
1192 TRACE("Created vertex shader %p.\n", object
);
1193 *ppVertexShader
= (IWineD3DVertexShader
*)object
;
1198 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice
*iface
,
1199 const DWORD
*pFunction
, const struct wined3d_shader_signature
*output_signature
,
1200 IWineD3DPixelShader
**ppPixelShader
, IUnknown
*parent
,
1201 const struct wined3d_parent_ops
*parent_ops
)
1203 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1204 IWineD3DPixelShaderImpl
*object
;
1207 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1210 ERR("Failed to allocate shader memory.\n");
1211 return E_OUTOFMEMORY
;
1214 hr
= pixelshader_init(object
, This
, pFunction
, output_signature
, parent
, parent_ops
);
1217 WARN("Failed to initialize pixel shader, hr %#x.\n", hr
);
1218 HeapFree(GetProcessHeap(), 0, object
);
1222 TRACE("Created pixel shader %p.\n", object
);
1223 *ppPixelShader
= (IWineD3DPixelShader
*)object
;
1228 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice
*iface
, DWORD Flags
,
1229 const PALETTEENTRY
*PalEnt
, IWineD3DPalette
**Palette
, IUnknown
*Parent
)
1231 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1232 IWineD3DPaletteImpl
*object
;
1234 TRACE("(%p)->(%x, %p, %p, %p)\n", This
, Flags
, PalEnt
, Palette
, Parent
);
1236 /* Create the new object */
1237 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DPaletteImpl
));
1239 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1240 return E_OUTOFMEMORY
;
1243 object
->lpVtbl
= &IWineD3DPalette_Vtbl
;
1245 object
->Flags
= Flags
;
1246 object
->parent
= Parent
;
1247 object
->device
= This
;
1248 object
->palNumEntries
= IWineD3DPaletteImpl_Size(Flags
);
1249 object
->hpal
= CreatePalette((const LOGPALETTE
*)&(object
->palVersion
));
1252 HeapFree( GetProcessHeap(), 0, object
);
1253 return E_OUTOFMEMORY
;
1256 hr
= IWineD3DPalette_SetEntries((IWineD3DPalette
*) object
, 0, 0, IWineD3DPaletteImpl_Size(Flags
), PalEnt
);
1258 IWineD3DPalette_Release((IWineD3DPalette
*) object
);
1262 *Palette
= (IWineD3DPalette
*) object
;
1267 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl
*This
, const char *filename
) {
1271 HDC dcb
= NULL
, dcs
= NULL
;
1272 WINEDDCOLORKEY colorkey
;
1274 hbm
= LoadImageA(NULL
, filename
, IMAGE_BITMAP
, 0, 0, LR_LOADFROMFILE
| LR_CREATEDIBSECTION
);
1277 GetObjectA(hbm
, sizeof(BITMAP
), &bm
);
1278 dcb
= CreateCompatibleDC(NULL
);
1280 SelectObject(dcb
, hbm
);
1284 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1285 * couldn't be loaded
1287 memset(&bm
, 0, sizeof(bm
));
1292 hr
= IWineD3DDevice_CreateSurface((IWineD3DDevice
*)This
, bm
.bmWidth
, bm
.bmHeight
, WINED3DFMT_B5G6R5_UNORM
, TRUE
,
1293 FALSE
, 0, &This
->logo_surface
, 0, WINED3DPOOL_DEFAULT
, WINED3DMULTISAMPLE_NONE
, 0, SURFACE_OPENGL
,
1294 NULL
, &wined3d_null_parent_ops
);
1296 ERR("Wine logo requested, but failed to create surface\n");
1301 hr
= IWineD3DSurface_GetDC(This
->logo_surface
, &dcs
);
1302 if(FAILED(hr
)) goto out
;
1303 BitBlt(dcs
, 0, 0, bm
.bmWidth
, bm
.bmHeight
, dcb
, 0, 0, SRCCOPY
);
1304 IWineD3DSurface_ReleaseDC(This
->logo_surface
, dcs
);
1306 colorkey
.dwColorSpaceLowValue
= 0;
1307 colorkey
.dwColorSpaceHighValue
= 0;
1308 IWineD3DSurface_SetColorKey(This
->logo_surface
, WINEDDCKEY_SRCBLT
, &colorkey
);
1310 /* Fill the surface with a white color to show that wined3d is there */
1311 IWineD3DDevice_ColorFill((IWineD3DDevice
*) This
, This
->logo_surface
, NULL
, 0xffffffff);
1324 /* Context activation is done by the caller. */
1325 static void create_dummy_textures(IWineD3DDeviceImpl
*This
)
1327 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
1329 /* Under DirectX you can have texture stage operations even if no texture is
1330 bound, whereas opengl will only do texture operations when a valid texture is
1331 bound. We emulate this by creating dummy textures and binding them to each
1332 texture stage, but disable all stages by default. Hence if a stage is enabled
1333 then the default texture will kick in until replaced by a SetTexture call */
1336 if (gl_info
->supported
[APPLE_CLIENT_STORAGE
])
1338 /* The dummy texture does not have client storage backing */
1339 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
1340 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1343 for (i
= 0; i
< gl_info
->limits
.textures
; ++i
)
1345 GLubyte white
= 255;
1347 /* Make appropriate texture active */
1348 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
+ i
));
1349 checkGLcall("glActiveTextureARB");
1351 /* Generate an opengl texture name */
1352 glGenTextures(1, &This
->dummyTextureName
[i
]);
1353 checkGLcall("glGenTextures");
1354 TRACE("Dummy Texture %d given name %d\n", i
, This
->dummyTextureName
[i
]);
1356 /* Generate a dummy 2d texture (not using 1d because they cause many
1357 * DRI drivers fall back to sw) */
1358 glBindTexture(GL_TEXTURE_2D
, This
->dummyTextureName
[i
]);
1359 checkGLcall("glBindTexture");
1361 glTexImage2D(GL_TEXTURE_2D
, 0, GL_LUMINANCE
, 1, 1, 0, GL_LUMINANCE
, GL_UNSIGNED_BYTE
, &white
);
1362 checkGLcall("glTexImage2D");
1365 if (gl_info
->supported
[APPLE_CLIENT_STORAGE
])
1367 /* Reenable because if supported it is enabled by default */
1368 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
1369 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1375 static HRESULT WINAPI
IWineD3DDeviceImpl_Init3D(IWineD3DDevice
*iface
,
1376 WINED3DPRESENT_PARAMETERS
*pPresentationParameters
)
1378 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1379 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
1380 IWineD3DSwapChainImpl
*swapchain
= NULL
;
1381 struct wined3d_context
*context
;
1386 TRACE("(%p)->(%p)\n", This
, pPresentationParameters
);
1388 if(This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
1389 if(!This
->adapter
->opengl
) return WINED3DERR_INVALIDCALL
;
1391 /* TODO: Test if OpenGL is compiled in and loaded */
1393 TRACE("(%p) : Creating stateblock\n", This
);
1394 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1395 hr
= IWineD3DDevice_CreateStateBlock(iface
,
1397 (IWineD3DStateBlock
**)&This
->stateBlock
,
1399 if (WINED3D_OK
!= hr
) { /* Note: No parent needed for initial internal stateblock */
1400 WARN("Failed to create stateblock\n");
1403 TRACE("(%p) : Created stateblock (%p)\n", This
, This
->stateBlock
);
1404 This
->updateStateBlock
= This
->stateBlock
;
1405 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
1407 This
->render_targets
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
1408 sizeof(IWineD3DSurface
*) * gl_info
->limits
.buffers
);
1409 This
->draw_buffers
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
1410 sizeof(GLenum
) * gl_info
->limits
.buffers
);
1412 This
->NumberOfPalettes
= 1;
1413 This
->palettes
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(PALETTEENTRY
*));
1414 if(!This
->palettes
|| !This
->render_targets
|| !This
->draw_buffers
) {
1415 ERR("Out of memory!\n");
1419 This
->palettes
[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY
) * 256);
1420 if(!This
->palettes
[0]) {
1421 ERR("Out of memory!\n");
1425 for (i
= 0; i
< 256; ++i
) {
1426 This
->palettes
[0][i
].peRed
= 0xFF;
1427 This
->palettes
[0][i
].peGreen
= 0xFF;
1428 This
->palettes
[0][i
].peBlue
= 0xFF;
1429 This
->palettes
[0][i
].peFlags
= 0xFF;
1431 This
->currentPalette
= 0;
1433 /* Initialize the texture unit mapping to a 1:1 mapping */
1434 for (state
= 0; state
< MAX_COMBINED_SAMPLERS
; ++state
)
1436 if (state
< gl_info
->limits
.fragment_samplers
)
1438 This
->texUnitMap
[state
] = state
;
1439 This
->rev_tex_unit_map
[state
] = state
;
1441 This
->texUnitMap
[state
] = WINED3D_UNMAPPED_STAGE
;
1442 This
->rev_tex_unit_map
[state
] = WINED3D_UNMAPPED_STAGE
;
1446 /* Setup the implicit swapchain. This also initializes a context. */
1447 TRACE("Creating implicit swapchain\n");
1448 hr
= IWineD3DDeviceParent_CreateSwapChain(This
->device_parent
,
1449 pPresentationParameters
, (IWineD3DSwapChain
**)&swapchain
);
1452 WARN("Failed to create implicit swapchain\n");
1456 This
->NumberOfSwapChains
= 1;
1457 This
->swapchains
= HeapAlloc(GetProcessHeap(), 0, This
->NumberOfSwapChains
* sizeof(IWineD3DSwapChain
*));
1458 if(!This
->swapchains
) {
1459 ERR("Out of memory!\n");
1462 This
->swapchains
[0] = (IWineD3DSwapChain
*) swapchain
;
1464 if(swapchain
->backBuffer
&& swapchain
->backBuffer
[0]) {
1465 TRACE("Setting rendertarget to %p\n", swapchain
->backBuffer
);
1466 This
->render_targets
[0] = swapchain
->backBuffer
[0];
1469 TRACE("Setting rendertarget to %p\n", swapchain
->frontBuffer
);
1470 This
->render_targets
[0] = swapchain
->frontBuffer
;
1472 IWineD3DSurface_AddRef(This
->render_targets
[0]);
1474 /* Depth Stencil support */
1475 This
->stencilBufferTarget
= This
->auto_depth_stencil_buffer
;
1476 if (NULL
!= This
->stencilBufferTarget
) {
1477 IWineD3DSurface_AddRef(This
->stencilBufferTarget
);
1480 hr
= This
->shader_backend
->shader_alloc_private(iface
);
1482 TRACE("Shader private data couldn't be allocated\n");
1485 hr
= This
->frag_pipe
->alloc_private(iface
);
1487 TRACE("Fragment pipeline private data couldn't be allocated\n");
1490 hr
= This
->blitter
->alloc_private(iface
);
1492 TRACE("Blitter private data couldn't be allocated\n");
1496 /* Set up some starting GL setup */
1498 /* Setup all the devices defaults */
1499 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock
*)This
->stateBlock
);
1501 context
= context_acquire(This
, swapchain
->frontBuffer
, CTXUSAGE_RESOURCELOAD
);
1503 create_dummy_textures(This
);
1507 /* Initialize the current view state */
1508 This
->view_ident
= 1;
1509 This
->contexts
[0]->last_was_rhw
= 0;
1510 glGetIntegerv(GL_MAX_LIGHTS
, &This
->maxConcurrentLights
);
1511 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1513 switch(wined3d_settings
.offscreen_rendering_mode
) {
1515 This
->offscreenBuffer
= GL_COLOR_ATTACHMENT0
;
1519 This
->offscreenBuffer
= GL_BACK
;
1522 case ORM_BACKBUFFER
:
1524 if (context_get_current()->aux_buffers
> 0)
1526 TRACE("Using auxilliary buffer for offscreen rendering\n");
1527 This
->offscreenBuffer
= GL_AUX0
;
1529 TRACE("Using back buffer for offscreen rendering\n");
1530 This
->offscreenBuffer
= GL_BACK
;
1535 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This
, This
);
1538 context_release(context
);
1540 /* Clear the screen */
1541 IWineD3DDevice_Clear((IWineD3DDevice
*) This
, 0, NULL
,
1542 WINED3DCLEAR_TARGET
| pPresentationParameters
->EnableAutoDepthStencil
? WINED3DCLEAR_ZBUFFER
| WINED3DCLEAR_STENCIL
: 0,
1545 This
->d3d_initialized
= TRUE
;
1547 if(wined3d_settings
.logo
) {
1548 IWineD3DDeviceImpl_LoadLogo(This
, wined3d_settings
.logo
);
1550 This
->highest_dirty_ps_const
= 0;
1551 This
->highest_dirty_vs_const
= 0;
1555 HeapFree(GetProcessHeap(), 0, This
->render_targets
);
1556 HeapFree(GetProcessHeap(), 0, This
->draw_buffers
);
1557 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
1558 This
->NumberOfSwapChains
= 0;
1559 if(This
->palettes
) {
1560 HeapFree(GetProcessHeap(), 0, This
->palettes
[0]);
1561 HeapFree(GetProcessHeap(), 0, This
->palettes
);
1563 This
->NumberOfPalettes
= 0;
1565 IWineD3DSwapChain_Release( (IWineD3DSwapChain
*) swapchain
);
1567 if(This
->stateBlock
) {
1568 IWineD3DStateBlock_Release((IWineD3DStateBlock
*) This
->stateBlock
);
1569 This
->stateBlock
= NULL
;
1571 if (This
->blit_priv
) {
1572 This
->blitter
->free_private(iface
);
1574 if (This
->fragment_priv
) {
1575 This
->frag_pipe
->free_private(iface
);
1577 if (This
->shader_priv
) {
1578 This
->shader_backend
->shader_free_private(iface
);
1583 static HRESULT WINAPI
IWineD3DDeviceImpl_InitGDI(IWineD3DDevice
*iface
,
1584 WINED3DPRESENT_PARAMETERS
*pPresentationParameters
)
1586 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1587 IWineD3DSwapChainImpl
*swapchain
= NULL
;
1590 /* Setup the implicit swapchain */
1591 TRACE("Creating implicit swapchain\n");
1592 hr
= IWineD3DDeviceParent_CreateSwapChain(This
->device_parent
,
1593 pPresentationParameters
, (IWineD3DSwapChain
**)&swapchain
);
1596 WARN("Failed to create implicit swapchain\n");
1600 This
->NumberOfSwapChains
= 1;
1601 This
->swapchains
= HeapAlloc(GetProcessHeap(), 0, This
->NumberOfSwapChains
* sizeof(IWineD3DSwapChain
*));
1602 if(!This
->swapchains
) {
1603 ERR("Out of memory!\n");
1606 This
->swapchains
[0] = (IWineD3DSwapChain
*) swapchain
;
1610 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
1614 static HRESULT WINAPI
device_unload_resource(IWineD3DResource
*resource
, void *ctx
)
1616 IWineD3DResource_UnLoad(resource
);
1617 IWineD3DResource_Release(resource
);
1621 static HRESULT WINAPI
IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice
*iface
,
1622 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain
)
1624 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1625 const struct wined3d_gl_info
*gl_info
;
1626 struct wined3d_context
*context
;
1629 TRACE("(%p)\n", This
);
1631 if(!This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
1633 /* I don't think that the interface guarantees that the device is destroyed from the same thread
1634 * it was created. Thus make sure a context is active for the glDelete* calls
1636 context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
1637 gl_info
= context
->gl_info
;
1639 if(This
->logo_surface
) IWineD3DSurface_Release(This
->logo_surface
);
1641 /* Unload resources */
1642 IWineD3DDevice_EnumResources(iface
, device_unload_resource
, NULL
);
1644 TRACE("Deleting high order patches\n");
1645 for(i
= 0; i
< PATCHMAP_SIZE
; i
++) {
1646 struct list
*e1
, *e2
;
1647 struct WineD3DRectPatch
*patch
;
1648 LIST_FOR_EACH_SAFE(e1
, e2
, &This
->patches
[i
]) {
1649 patch
= LIST_ENTRY(e1
, struct WineD3DRectPatch
, entry
);
1650 IWineD3DDevice_DeletePatch(iface
, patch
->Handle
);
1654 /* Delete the palette conversion shader if it is around */
1655 if(This
->paletteConversionShader
) {
1657 GL_EXTCALL(glDeleteProgramsARB(1, &This
->paletteConversionShader
));
1659 This
->paletteConversionShader
= 0;
1662 /* Delete the pbuffer context if there is any */
1663 if(This
->pbufferContext
) context_destroy(This
, This
->pbufferContext
);
1665 /* Delete the mouse cursor texture */
1666 if(This
->cursorTexture
) {
1668 glDeleteTextures(1, &This
->cursorTexture
);
1670 This
->cursorTexture
= 0;
1673 for (sampler
= 0; sampler
< MAX_FRAGMENT_SAMPLERS
; ++sampler
) {
1674 IWineD3DDevice_SetTexture(iface
, sampler
, NULL
);
1676 for (sampler
= 0; sampler
< MAX_VERTEX_SAMPLERS
; ++sampler
) {
1677 IWineD3DDevice_SetTexture(iface
, WINED3DVERTEXTEXTURESAMPLER0
+ sampler
, NULL
);
1680 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
1681 * private data, it might contain opengl pointers
1683 if(This
->depth_blt_texture
) {
1685 glDeleteTextures(1, &This
->depth_blt_texture
);
1687 This
->depth_blt_texture
= 0;
1689 if (This
->depth_blt_rb
) {
1691 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &This
->depth_blt_rb
);
1693 This
->depth_blt_rb
= 0;
1694 This
->depth_blt_rb_w
= 0;
1695 This
->depth_blt_rb_h
= 0;
1698 /* Release the update stateblock */
1699 if(IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
) > 0){
1700 if(This
->updateStateBlock
!= This
->stateBlock
)
1701 FIXME("(%p) Something's still holding the Update stateblock\n",This
);
1703 This
->updateStateBlock
= NULL
;
1705 { /* because were not doing proper internal refcounts releasing the primary state block
1706 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1707 to set this->stateBlock = NULL; first */
1708 IWineD3DStateBlock
*stateBlock
= (IWineD3DStateBlock
*)This
->stateBlock
;
1709 This
->stateBlock
= NULL
;
1711 /* Release the stateblock */
1712 if(IWineD3DStateBlock_Release(stateBlock
) > 0){
1713 FIXME("(%p) Something's still holding the Update stateblock\n",This
);
1717 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
1718 This
->blitter
->free_private(iface
);
1719 This
->frag_pipe
->free_private(iface
);
1720 This
->shader_backend
->shader_free_private(iface
);
1722 /* Release the buffers (with sanity checks)*/
1723 TRACE("Releasing the depth stencil buffer at %p\n", This
->stencilBufferTarget
);
1724 if(This
->stencilBufferTarget
!= NULL
&& (IWineD3DSurface_Release(This
->stencilBufferTarget
) >0)){
1725 if(This
->auto_depth_stencil_buffer
!= This
->stencilBufferTarget
)
1726 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This
);
1728 This
->stencilBufferTarget
= NULL
;
1730 TRACE("Releasing the render target at %p\n", This
->render_targets
[0]);
1731 if(IWineD3DSurface_Release(This
->render_targets
[0]) >0){
1732 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1734 TRACE("Setting rendertarget to NULL\n");
1735 This
->render_targets
[0] = NULL
;
1737 if (This
->auto_depth_stencil_buffer
) {
1738 if (IWineD3DSurface_Release(This
->auto_depth_stencil_buffer
) > 0)
1740 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This
);
1742 This
->auto_depth_stencil_buffer
= NULL
;
1745 context_release(context
);
1747 for(i
=0; i
< This
->NumberOfSwapChains
; i
++) {
1748 TRACE("Releasing the implicit swapchain %d\n", i
);
1749 if (D3DCB_DestroySwapChain(This
->swapchains
[i
]) > 0) {
1750 FIXME("(%p) Something's still holding the implicit swapchain\n", This
);
1754 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
1755 This
->swapchains
= NULL
;
1756 This
->NumberOfSwapChains
= 0;
1758 for (i
= 0; i
< This
->NumberOfPalettes
; i
++) HeapFree(GetProcessHeap(), 0, This
->palettes
[i
]);
1759 HeapFree(GetProcessHeap(), 0, This
->palettes
);
1760 This
->palettes
= NULL
;
1761 This
->NumberOfPalettes
= 0;
1763 HeapFree(GetProcessHeap(), 0, This
->render_targets
);
1764 HeapFree(GetProcessHeap(), 0, This
->draw_buffers
);
1765 This
->render_targets
= NULL
;
1766 This
->draw_buffers
= NULL
;
1768 This
->d3d_initialized
= FALSE
;
1772 static HRESULT WINAPI
IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice
*iface
, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain
) {
1773 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1776 for(i
=0; i
< This
->NumberOfSwapChains
; i
++) {
1777 TRACE("Releasing the implicit swapchain %d\n", i
);
1778 if (D3DCB_DestroySwapChain(This
->swapchains
[i
]) > 0) {
1779 FIXME("(%p) Something's still holding the implicit swapchain\n", This
);
1783 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
1784 This
->swapchains
= NULL
;
1785 This
->NumberOfSwapChains
= 0;
1789 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
1790 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
1791 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
1793 * There is no way to deactivate thread safety once it is enabled.
1795 static void WINAPI
IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice
*iface
) {
1796 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1798 /*For now just store the flag(needed in case of ddraw) */
1799 This
->createParms
.BehaviorFlags
|= WINED3DCREATE_MULTITHREADED
;
1804 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
,
1805 const WINED3DDISPLAYMODE
* pMode
) {
1807 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1809 const struct GlPixelFormatDesc
*format_desc
= getFormatDescEntry(pMode
->Format
, &This
->adapter
->gl_info
);
1812 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This
, iSwapChain
, pMode
, pMode
->Width
, pMode
->Height
, pMode
->RefreshRate
, debug_d3dformat(pMode
->Format
));
1814 /* Resize the screen even without a window:
1815 * The app could have unset it with SetCooperativeLevel, but not called
1816 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1817 * but we don't have any hwnd
1820 memset(&devmode
, 0, sizeof(devmode
));
1821 devmode
.dmSize
= sizeof(devmode
);
1822 devmode
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
1823 devmode
.dmBitsPerPel
= format_desc
->byte_count
* 8;
1824 devmode
.dmPelsWidth
= pMode
->Width
;
1825 devmode
.dmPelsHeight
= pMode
->Height
;
1827 devmode
.dmDisplayFrequency
= pMode
->RefreshRate
;
1828 if (pMode
->RefreshRate
!= 0) {
1829 devmode
.dmFields
|= DM_DISPLAYFREQUENCY
;
1832 /* Only change the mode if necessary */
1833 if( (This
->ddraw_width
== pMode
->Width
) &&
1834 (This
->ddraw_height
== pMode
->Height
) &&
1835 (This
->ddraw_format
== pMode
->Format
) &&
1836 (pMode
->RefreshRate
== 0) ) {
1840 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
);
1841 if (ret
!= DISP_CHANGE_SUCCESSFUL
) {
1842 if(devmode
.dmDisplayFrequency
!= 0) {
1843 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1844 devmode
.dmFields
&= ~DM_DISPLAYFREQUENCY
;
1845 devmode
.dmDisplayFrequency
= 0;
1846 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
) != DISP_CHANGE_SUCCESSFUL
;
1848 if(ret
!= DISP_CHANGE_SUCCESSFUL
) {
1849 return WINED3DERR_NOTAVAILABLE
;
1853 /* Store the new values */
1854 This
->ddraw_width
= pMode
->Width
;
1855 This
->ddraw_height
= pMode
->Height
;
1856 This
->ddraw_format
= pMode
->Format
;
1858 /* And finally clip mouse to our screen */
1859 SetRect(&clip_rc
, 0, 0, pMode
->Width
, pMode
->Height
);
1860 ClipCursor(&clip_rc
);
1865 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice
*iface
, IWineD3D
**ppD3D
) {
1866 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1867 *ppD3D
= This
->wined3d
;
1868 TRACE("Returning %p.\n", *ppD3D
);
1869 IWineD3D_AddRef(*ppD3D
);
1873 static UINT WINAPI
IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice
*iface
) {
1874 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1876 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This
,
1877 (This
->adapter
->TextureRam
/(1024*1024)),
1878 ((This
->adapter
->TextureRam
- This
->adapter
->UsedTextureRam
) / (1024*1024)));
1879 /* return simulated texture memory left */
1880 return (This
->adapter
->TextureRam
- This
->adapter
->UsedTextureRam
);
1884 * Get / Set Stream Source
1886 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice
*iface
, UINT StreamNumber
,
1887 IWineD3DBuffer
*pStreamData
, UINT OffsetInBytes
, UINT Stride
)
1889 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1890 IWineD3DBuffer
*oldSrc
;
1892 if (StreamNumber
>= MAX_STREAMS
) {
1893 WARN("Stream out of range %d\n", StreamNumber
);
1894 return WINED3DERR_INVALIDCALL
;
1895 } else if(OffsetInBytes
& 0x3) {
1896 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes
);
1897 return WINED3DERR_INVALIDCALL
;
1900 oldSrc
= This
->updateStateBlock
->streamSource
[StreamNumber
];
1901 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This
, StreamNumber
, oldSrc
, pStreamData
, OffsetInBytes
, Stride
);
1903 This
->updateStateBlock
->changed
.streamSource
|= 1 << StreamNumber
;
1905 if(oldSrc
== pStreamData
&&
1906 This
->updateStateBlock
->streamStride
[StreamNumber
] == Stride
&&
1907 This
->updateStateBlock
->streamOffset
[StreamNumber
] == OffsetInBytes
) {
1908 TRACE("Application is setting the old values over, nothing to do\n");
1912 This
->updateStateBlock
->streamSource
[StreamNumber
] = pStreamData
;
1914 This
->updateStateBlock
->streamStride
[StreamNumber
] = Stride
;
1915 This
->updateStateBlock
->streamOffset
[StreamNumber
] = OffsetInBytes
;
1918 /* Handle recording of state blocks */
1919 if (This
->isRecordingState
) {
1920 TRACE("Recording... not performing anything\n");
1921 if (pStreamData
) IWineD3DBuffer_AddRef(pStreamData
);
1922 if (oldSrc
) IWineD3DBuffer_Release(oldSrc
);
1926 if (pStreamData
!= NULL
) {
1927 InterlockedIncrement(&((struct wined3d_buffer
*)pStreamData
)->bind_count
);
1928 IWineD3DBuffer_AddRef(pStreamData
);
1930 if (oldSrc
!= NULL
) {
1931 InterlockedDecrement(&((struct wined3d_buffer
*)oldSrc
)->bind_count
);
1932 IWineD3DBuffer_Release(oldSrc
);
1935 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
1940 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice
*iface
,
1941 UINT StreamNumber
, IWineD3DBuffer
**pStream
, UINT
*pOffset
, UINT
*pStride
)
1943 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1945 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This
, StreamNumber
,
1946 This
->stateBlock
->streamSource
[StreamNumber
],
1947 This
->stateBlock
->streamOffset
[StreamNumber
],
1948 This
->stateBlock
->streamStride
[StreamNumber
]);
1950 if (StreamNumber
>= MAX_STREAMS
) {
1951 WARN("Stream out of range %d\n", StreamNumber
);
1952 return WINED3DERR_INVALIDCALL
;
1954 *pStream
= This
->stateBlock
->streamSource
[StreamNumber
];
1955 *pStride
= This
->stateBlock
->streamStride
[StreamNumber
];
1957 *pOffset
= This
->stateBlock
->streamOffset
[StreamNumber
];
1960 if (*pStream
!= NULL
) {
1961 IWineD3DBuffer_AddRef(*pStream
); /* We have created a new reference to the VB */
1966 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT Divider
) {
1967 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1968 UINT oldFlags
= This
->updateStateBlock
->streamFlags
[StreamNumber
];
1969 UINT oldFreq
= This
->updateStateBlock
->streamFreq
[StreamNumber
];
1971 /* Verify input at least in d3d9 this is invalid*/
1972 if( (Divider
& WINED3DSTREAMSOURCE_INSTANCEDATA
) && (Divider
& WINED3DSTREAMSOURCE_INDEXEDDATA
)){
1973 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
1974 return WINED3DERR_INVALIDCALL
;
1976 if( (Divider
& WINED3DSTREAMSOURCE_INSTANCEDATA
) && StreamNumber
== 0 ){
1977 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
1978 return WINED3DERR_INVALIDCALL
;
1981 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
1982 return WINED3DERR_INVALIDCALL
;
1985 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This
, StreamNumber
, Divider
);
1986 This
->updateStateBlock
->streamFlags
[StreamNumber
] = Divider
& (WINED3DSTREAMSOURCE_INSTANCEDATA
| WINED3DSTREAMSOURCE_INDEXEDDATA
);
1988 This
->updateStateBlock
->changed
.streamFreq
|= 1 << StreamNumber
;
1989 This
->updateStateBlock
->streamFreq
[StreamNumber
] = Divider
& 0x7FFFFF;
1991 if(This
->updateStateBlock
->streamFreq
[StreamNumber
] != oldFreq
||
1992 This
->updateStateBlock
->streamFlags
[StreamNumber
] != oldFlags
) {
1993 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
1999 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT
* Divider
) {
2000 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2002 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This
, StreamNumber
, Divider
);
2003 *Divider
= This
->updateStateBlock
->streamFreq
[StreamNumber
] | This
->updateStateBlock
->streamFlags
[StreamNumber
];
2005 TRACE("(%p) : returning %d\n", This
, *Divider
);
2011 * Get / Set & Multiply Transform
2013 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE d3dts
, CONST WINED3DMATRIX
* lpmatrix
) {
2014 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2016 /* Most of this routine, comments included copied from ddraw tree initially: */
2017 TRACE("(%p) : Transform State=%s\n", This
, debug_d3dtstype(d3dts
));
2019 /* Handle recording of state blocks */
2020 if (This
->isRecordingState
) {
2021 TRACE("Recording... not performing anything\n");
2022 This
->updateStateBlock
->changed
.transform
[d3dts
>> 5] |= 1 << (d3dts
& 0x1f);
2023 This
->updateStateBlock
->transforms
[d3dts
] = *lpmatrix
;
2028 * If the new matrix is the same as the current one,
2029 * we cut off any further processing. this seems to be a reasonable
2030 * optimization because as was noticed, some apps (warcraft3 for example)
2031 * tend towards setting the same matrix repeatedly for some reason.
2033 * From here on we assume that the new matrix is different, wherever it matters.
2035 if (!memcmp(&This
->stateBlock
->transforms
[d3dts
].u
.m
[0][0], lpmatrix
, sizeof(WINED3DMATRIX
))) {
2036 TRACE("The app is setting the same matrix over again\n");
2039 conv_mat(lpmatrix
, &This
->stateBlock
->transforms
[d3dts
].u
.m
[0][0]);
2043 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2044 where ViewMat = Camera space, WorldMat = world space.
2046 In OpenGL, camera and world space is combined into GL_MODELVIEW
2047 matrix. The Projection matrix stay projection matrix.
2050 /* Capture the times we can just ignore the change for now */
2051 if (d3dts
== WINED3DTS_VIEW
) { /* handle the VIEW matrix */
2052 This
->view_ident
= !memcmp(lpmatrix
, identity
, 16 * sizeof(float));
2053 /* Handled by the state manager */
2056 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TRANSFORM(d3dts
));
2060 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, WINED3DMATRIX
* pMatrix
) {
2061 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2062 TRACE("(%p) : for Transform State %s\n", This
, debug_d3dtstype(State
));
2063 *pMatrix
= This
->stateBlock
->transforms
[State
];
2067 static HRESULT WINAPI
IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, CONST WINED3DMATRIX
* pMatrix
) {
2068 const WINED3DMATRIX
*mat
= NULL
;
2071 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2072 * below means it will be recorded in a state block change, but it
2073 * works regardless where it is recorded.
2074 * If this is found to be wrong, change to StateBlock.
2076 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2077 TRACE("(%p) : For state %s\n", This
, debug_d3dtstype(State
));
2079 if (State
<= HIGHEST_TRANSFORMSTATE
)
2081 mat
= &This
->updateStateBlock
->transforms
[State
];
2083 FIXME("Unhandled transform state!!\n");
2086 multiply_matrix(&temp
, mat
, pMatrix
);
2088 /* Apply change via set transform - will reapply to eg. lights this way */
2089 return IWineD3DDeviceImpl_SetTransform(iface
, State
, &temp
);
2095 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2096 you can reference any indexes you want as long as that number max are enabled at any
2097 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2098 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2099 but when recording, just build a chain pretty much of commands to be replayed. */
2101 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLight(IWineD3DDevice
*iface
, DWORD Index
, CONST WINED3DLIGHT
* pLight
) {
2103 struct wined3d_light_info
*object
= NULL
;
2104 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2107 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2108 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This
, Index
, pLight
, Hi
);
2110 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2114 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2115 return WINED3DERR_INVALIDCALL
;
2118 switch(pLight
->Type
) {
2119 case WINED3DLIGHT_POINT
:
2120 case WINED3DLIGHT_SPOT
:
2121 case WINED3DLIGHT_PARALLELPOINT
:
2122 case WINED3DLIGHT_GLSPOT
:
2123 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2126 if (pLight
->Attenuation0
< 0.0f
|| pLight
->Attenuation1
< 0.0f
|| pLight
->Attenuation2
< 0.0f
)
2128 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2129 return WINED3DERR_INVALIDCALL
;
2133 case WINED3DLIGHT_DIRECTIONAL
:
2134 /* Ignores attenuation */
2138 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2139 return WINED3DERR_INVALIDCALL
;
2142 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
])
2144 object
= LIST_ENTRY(e
, struct wined3d_light_info
, entry
);
2145 if(object
->OriginalIndex
== Index
) break;
2150 TRACE("Adding new light\n");
2151 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
2153 ERR("Out of memory error when allocating a light\n");
2154 return E_OUTOFMEMORY
;
2156 list_add_head(&This
->updateStateBlock
->lightMap
[Hi
], &object
->entry
);
2157 object
->glIndex
= -1;
2158 object
->OriginalIndex
= Index
;
2161 /* Initialize the object */
2162 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
,
2163 pLight
->Diffuse
.r
, pLight
->Diffuse
.g
, pLight
->Diffuse
.b
, pLight
->Diffuse
.a
,
2164 pLight
->Specular
.r
, pLight
->Specular
.g
, pLight
->Specular
.b
, pLight
->Specular
.a
,
2165 pLight
->Ambient
.r
, pLight
->Ambient
.g
, pLight
->Ambient
.b
, pLight
->Ambient
.a
);
2166 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight
->Position
.x
, pLight
->Position
.y
, pLight
->Position
.z
,
2167 pLight
->Direction
.x
, pLight
->Direction
.y
, pLight
->Direction
.z
);
2168 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight
->Range
, pLight
->Falloff
, pLight
->Theta
, pLight
->Phi
);
2170 /* Save away the information */
2171 object
->OriginalParms
= *pLight
;
2173 switch (pLight
->Type
) {
2174 case WINED3DLIGHT_POINT
:
2176 object
->lightPosn
[0] = pLight
->Position
.x
;
2177 object
->lightPosn
[1] = pLight
->Position
.y
;
2178 object
->lightPosn
[2] = pLight
->Position
.z
;
2179 object
->lightPosn
[3] = 1.0f
;
2180 object
->cutoff
= 180.0f
;
2184 case WINED3DLIGHT_DIRECTIONAL
:
2186 object
->lightPosn
[0] = -pLight
->Direction
.x
;
2187 object
->lightPosn
[1] = -pLight
->Direction
.y
;
2188 object
->lightPosn
[2] = -pLight
->Direction
.z
;
2189 object
->lightPosn
[3] = 0.0f
;
2190 object
->exponent
= 0.0f
;
2191 object
->cutoff
= 180.0f
;
2194 case WINED3DLIGHT_SPOT
:
2196 object
->lightPosn
[0] = pLight
->Position
.x
;
2197 object
->lightPosn
[1] = pLight
->Position
.y
;
2198 object
->lightPosn
[2] = pLight
->Position
.z
;
2199 object
->lightPosn
[3] = 1.0f
;
2202 object
->lightDirn
[0] = pLight
->Direction
.x
;
2203 object
->lightDirn
[1] = pLight
->Direction
.y
;
2204 object
->lightDirn
[2] = pLight
->Direction
.z
;
2205 object
->lightDirn
[3] = 1.0f
;
2208 * opengl-ish and d3d-ish spot lights use too different models for the
2209 * light "intensity" as a function of the angle towards the main light direction,
2210 * so we only can approximate very roughly.
2211 * however spot lights are rather rarely used in games (if ever used at all).
2212 * furthermore if still used, probably nobody pays attention to such details.
2214 if (pLight
->Falloff
== 0) {
2215 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2216 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2217 * will always be 1.0 for both of them, and we don't have to care for the
2218 * rest of the rather complex calculation
2220 object
->exponent
= 0.0f
;
2222 rho
= pLight
->Theta
+ (pLight
->Phi
- pLight
->Theta
)/(2*pLight
->Falloff
);
2223 if (rho
< 0.0001f
) rho
= 0.0001f
;
2224 object
->exponent
= -0.3f
/logf(cosf(rho
/2));
2226 if (object
->exponent
> 128.0f
)
2228 object
->exponent
= 128.0f
;
2230 object
->cutoff
= pLight
->Phi
*90/M_PI
;
2236 FIXME("Unrecognized light type %d\n", pLight
->Type
);
2239 /* Update the live definitions if the light is currently assigned a glIndex */
2240 if (object
->glIndex
!= -1 && !This
->isRecordingState
) {
2241 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(object
->glIndex
));
2246 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLight(IWineD3DDevice
*iface
, DWORD Index
, WINED3DLIGHT
*pLight
)
2248 struct wined3d_light_info
*lightInfo
= NULL
;
2249 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2250 DWORD Hi
= LIGHTMAP_HASHFUNC(Index
);
2252 TRACE("(%p) : Idx(%d), pLight(%p)\n", This
, Index
, pLight
);
2254 LIST_FOR_EACH(e
, &This
->stateBlock
->lightMap
[Hi
])
2256 lightInfo
= LIST_ENTRY(e
, struct wined3d_light_info
, entry
);
2257 if(lightInfo
->OriginalIndex
== Index
) break;
2261 if (lightInfo
== NULL
) {
2262 TRACE("Light information requested but light not defined\n");
2263 return WINED3DERR_INVALIDCALL
;
2266 *pLight
= lightInfo
->OriginalParms
;
2271 * Get / Set Light Enable
2272 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2274 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice
*iface
, DWORD Index
, BOOL Enable
)
2276 struct wined3d_light_info
*lightInfo
= NULL
;
2277 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2278 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2280 TRACE("(%p) : Idx(%d), enable? %d\n", This
, Index
, Enable
);
2282 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
])
2284 lightInfo
= LIST_ENTRY(e
, struct wined3d_light_info
, entry
);
2285 if(lightInfo
->OriginalIndex
== Index
) break;
2288 TRACE("Found light: %p\n", lightInfo
);
2290 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2291 if (lightInfo
== NULL
) {
2293 TRACE("Light enabled requested but light not defined, so defining one!\n");
2294 IWineD3DDeviceImpl_SetLight(iface
, Index
, &WINED3D_default_light
);
2296 /* Search for it again! Should be fairly quick as near head of list */
2297 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
])
2299 lightInfo
= LIST_ENTRY(e
, struct wined3d_light_info
, entry
);
2300 if(lightInfo
->OriginalIndex
== Index
) break;
2303 if (lightInfo
== NULL
) {
2304 FIXME("Adding default lights has failed dismally\n");
2305 return WINED3DERR_INVALIDCALL
;
2310 if(lightInfo
->glIndex
!= -1) {
2311 if(!This
->isRecordingState
) {
2312 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(lightInfo
->glIndex
));
2315 This
->updateStateBlock
->activeLights
[lightInfo
->glIndex
] = NULL
;
2316 lightInfo
->glIndex
= -1;
2318 TRACE("Light already disabled, nothing to do\n");
2320 lightInfo
->enabled
= FALSE
;
2322 lightInfo
->enabled
= TRUE
;
2323 if (lightInfo
->glIndex
!= -1) {
2325 TRACE("Nothing to do as light was enabled\n");
2328 /* Find a free gl light */
2329 for(i
= 0; i
< This
->maxConcurrentLights
; i
++) {
2330 if(This
->updateStateBlock
->activeLights
[i
] == NULL
) {
2331 This
->updateStateBlock
->activeLights
[i
] = lightInfo
;
2332 lightInfo
->glIndex
= i
;
2336 if(lightInfo
->glIndex
== -1) {
2337 /* Our tests show that Windows returns D3D_OK in this situation, even with
2338 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2339 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2340 * as well for those lights.
2342 * TODO: Test how this affects rendering
2344 WARN("Too many concurrently active lights\n");
2348 /* i == lightInfo->glIndex */
2349 if(!This
->isRecordingState
) {
2350 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(i
));
2358 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice
*iface
, DWORD Index
,BOOL
* pEnable
)
2360 struct wined3d_light_info
*lightInfo
= NULL
;
2361 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2363 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2364 TRACE("(%p) : for idx(%d)\n", This
, Index
);
2366 LIST_FOR_EACH(e
, &This
->stateBlock
->lightMap
[Hi
])
2368 lightInfo
= LIST_ENTRY(e
, struct wined3d_light_info
, entry
);
2369 if(lightInfo
->OriginalIndex
== Index
) break;
2373 if (lightInfo
== NULL
) {
2374 TRACE("Light enabled state requested but light not defined\n");
2375 return WINED3DERR_INVALIDCALL
;
2377 /* true is 128 according to SetLightEnable */
2378 *pEnable
= lightInfo
->enabled
? 128 : 0;
2383 * Get / Set Clip Planes
2385 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, CONST
float *pPlane
) {
2386 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2387 TRACE("(%p) : for idx %d, %p\n", This
, Index
, pPlane
);
2389 /* Validate Index */
2390 if (Index
>= This
->adapter
->gl_info
.limits
.clipplanes
)
2392 TRACE("Application has requested clipplane this device doesn't support\n");
2393 return WINED3DERR_INVALIDCALL
;
2396 This
->updateStateBlock
->changed
.clipplane
|= 1 << Index
;
2398 if(This
->updateStateBlock
->clipplane
[Index
][0] == pPlane
[0] &&
2399 This
->updateStateBlock
->clipplane
[Index
][1] == pPlane
[1] &&
2400 This
->updateStateBlock
->clipplane
[Index
][2] == pPlane
[2] &&
2401 This
->updateStateBlock
->clipplane
[Index
][3] == pPlane
[3]) {
2402 TRACE("Application is setting old values over, nothing to do\n");
2406 This
->updateStateBlock
->clipplane
[Index
][0] = pPlane
[0];
2407 This
->updateStateBlock
->clipplane
[Index
][1] = pPlane
[1];
2408 This
->updateStateBlock
->clipplane
[Index
][2] = pPlane
[2];
2409 This
->updateStateBlock
->clipplane
[Index
][3] = pPlane
[3];
2411 /* Handle recording of state blocks */
2412 if (This
->isRecordingState
) {
2413 TRACE("Recording... not performing anything\n");
2417 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_CLIPPLANE(Index
));
2422 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, float *pPlane
) {
2423 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2424 TRACE("(%p) : for idx %d\n", This
, Index
);
2426 /* Validate Index */
2427 if (Index
>= This
->adapter
->gl_info
.limits
.clipplanes
)
2429 TRACE("Application has requested clipplane this device doesn't support\n");
2430 return WINED3DERR_INVALIDCALL
;
2433 pPlane
[0] = This
->stateBlock
->clipplane
[Index
][0];
2434 pPlane
[1] = This
->stateBlock
->clipplane
[Index
][1];
2435 pPlane
[2] = This
->stateBlock
->clipplane
[Index
][2];
2436 pPlane
[3] = This
->stateBlock
->clipplane
[Index
][3];
2441 * Get / Set Clip Plane Status
2442 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2444 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice
*iface
, CONST WINED3DCLIPSTATUS
* pClipStatus
) {
2445 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2446 FIXME("(%p) : stub\n", This
);
2447 if (NULL
== pClipStatus
) {
2448 return WINED3DERR_INVALIDCALL
;
2450 This
->updateStateBlock
->clip_status
.ClipUnion
= pClipStatus
->ClipUnion
;
2451 This
->updateStateBlock
->clip_status
.ClipIntersection
= pClipStatus
->ClipIntersection
;
2455 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice
*iface
, WINED3DCLIPSTATUS
* pClipStatus
) {
2456 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2457 FIXME("(%p) : stub\n", This
);
2458 if (NULL
== pClipStatus
) {
2459 return WINED3DERR_INVALIDCALL
;
2461 pClipStatus
->ClipUnion
= This
->updateStateBlock
->clip_status
.ClipUnion
;
2462 pClipStatus
->ClipIntersection
= This
->updateStateBlock
->clip_status
.ClipIntersection
;
2467 * Get / Set Material
2469 static HRESULT WINAPI
IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice
*iface
, CONST WINED3DMATERIAL
* pMaterial
) {
2470 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2472 This
->updateStateBlock
->changed
.material
= TRUE
;
2473 This
->updateStateBlock
->material
= *pMaterial
;
2475 /* Handle recording of state blocks */
2476 if (This
->isRecordingState
) {
2477 TRACE("Recording... not performing anything\n");
2481 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_MATERIAL
);
2485 static HRESULT WINAPI
IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice
*iface
, WINED3DMATERIAL
* pMaterial
) {
2486 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2487 *pMaterial
= This
->updateStateBlock
->material
;
2488 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This
, pMaterial
->Diffuse
.r
, pMaterial
->Diffuse
.g
,
2489 pMaterial
->Diffuse
.b
, pMaterial
->Diffuse
.a
);
2490 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This
, pMaterial
->Ambient
.r
, pMaterial
->Ambient
.g
,
2491 pMaterial
->Ambient
.b
, pMaterial
->Ambient
.a
);
2492 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This
, pMaterial
->Specular
.r
, pMaterial
->Specular
.g
,
2493 pMaterial
->Specular
.b
, pMaterial
->Specular
.a
);
2494 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This
, pMaterial
->Emissive
.r
, pMaterial
->Emissive
.g
,
2495 pMaterial
->Emissive
.b
, pMaterial
->Emissive
.a
);
2496 TRACE("(%p) : Power (%f)\n", This
, pMaterial
->Power
);
2504 static HRESULT WINAPI
IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice
*iface
,
2505 IWineD3DBuffer
*pIndexData
, WINED3DFORMAT fmt
)
2507 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2508 IWineD3DBuffer
*oldIdxs
;
2510 TRACE("(%p) : Setting to %p\n", This
, pIndexData
);
2511 oldIdxs
= This
->updateStateBlock
->pIndexData
;
2513 This
->updateStateBlock
->changed
.indices
= TRUE
;
2514 This
->updateStateBlock
->pIndexData
= pIndexData
;
2515 This
->updateStateBlock
->IndexFmt
= fmt
;
2517 /* Handle recording of state blocks */
2518 if (This
->isRecordingState
) {
2519 TRACE("Recording... not performing anything\n");
2520 if(pIndexData
) IWineD3DBuffer_AddRef(pIndexData
);
2521 if(oldIdxs
) IWineD3DBuffer_Release(oldIdxs
);
2525 if(oldIdxs
!= pIndexData
) {
2526 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
2528 InterlockedIncrement(&((struct wined3d_buffer
*)pIndexData
)->bind_count
);
2529 IWineD3DBuffer_AddRef(pIndexData
);
2532 InterlockedDecrement(&((struct wined3d_buffer
*)oldIdxs
)->bind_count
);
2533 IWineD3DBuffer_Release(oldIdxs
);
2540 static HRESULT WINAPI
IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice
*iface
, IWineD3DBuffer
**ppIndexData
)
2542 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2544 *ppIndexData
= This
->stateBlock
->pIndexData
;
2546 /* up ref count on ppindexdata */
2548 IWineD3DBuffer_AddRef(*ppIndexData
);
2549 TRACE("(%p) index data set to %p\n", This
, ppIndexData
);
2551 TRACE("(%p) No index data set\n", This
);
2553 TRACE("Returning %p\n", *ppIndexData
);
2558 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2559 static HRESULT WINAPI
IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice
*iface
, INT BaseIndex
) {
2560 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2561 TRACE("(%p)->(%d)\n", This
, BaseIndex
);
2563 if(This
->updateStateBlock
->baseVertexIndex
== BaseIndex
) {
2564 TRACE("Application is setting the old value over, nothing to do\n");
2568 This
->updateStateBlock
->baseVertexIndex
= BaseIndex
;
2570 if (This
->isRecordingState
) {
2571 TRACE("Recording... not performing anything\n");
2574 /* The base vertex index affects the stream sources */
2575 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2579 static HRESULT WINAPI
IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice
*iface
, INT
* base_index
) {
2580 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2581 TRACE("(%p) : base_index %p\n", This
, base_index
);
2583 *base_index
= This
->stateBlock
->baseVertexIndex
;
2585 TRACE("Returning %u\n", *base_index
);
2591 * Get / Set Viewports
2593 static HRESULT WINAPI
IWineD3DDeviceImpl_SetViewport(IWineD3DDevice
*iface
, CONST WINED3DVIEWPORT
* pViewport
) {
2594 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2596 TRACE("(%p)\n", This
);
2597 This
->updateStateBlock
->changed
.viewport
= TRUE
;
2598 This
->updateStateBlock
->viewport
= *pViewport
;
2600 /* Handle recording of state blocks */
2601 if (This
->isRecordingState
) {
2602 TRACE("Recording... not performing anything\n");
2606 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This
,
2607 pViewport
->X
, pViewport
->Y
, pViewport
->Width
, pViewport
->Height
, pViewport
->MinZ
, pViewport
->MaxZ
);
2609 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VIEWPORT
);
2614 static HRESULT WINAPI
IWineD3DDeviceImpl_GetViewport(IWineD3DDevice
*iface
, WINED3DVIEWPORT
* pViewport
) {
2615 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2616 TRACE("(%p)\n", This
);
2617 *pViewport
= This
->stateBlock
->viewport
;
2622 * Get / Set Render States
2623 * TODO: Verify against dx9 definitions
2625 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice
*iface
, WINED3DRENDERSTATETYPE State
, DWORD Value
) {
2627 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2628 DWORD oldValue
= This
->stateBlock
->renderState
[State
];
2630 TRACE("(%p)->state = %s(%d), value = %d\n", This
, debug_d3drenderstate(State
), State
, Value
);
2632 This
->updateStateBlock
->changed
.renderState
[State
>> 5] |= 1 << (State
& 0x1f);
2633 This
->updateStateBlock
->renderState
[State
] = Value
;
2635 /* Handle recording of state blocks */
2636 if (This
->isRecordingState
) {
2637 TRACE("Recording... not performing anything\n");
2641 /* Compared here and not before the assignment to allow proper stateblock recording */
2642 if(Value
== oldValue
) {
2643 TRACE("Application is setting the old value over, nothing to do\n");
2645 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(State
));
2651 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice
*iface
, WINED3DRENDERSTATETYPE State
, DWORD
*pValue
) {
2652 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2653 TRACE("(%p) for State %d = %d\n", This
, State
, This
->stateBlock
->renderState
[State
]);
2654 *pValue
= This
->stateBlock
->renderState
[State
];
2659 * Get / Set Sampler States
2660 * TODO: Verify against dx9 definitions
2663 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD Value
) {
2664 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2667 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2668 This
, Sampler
, debug_d3dsamplerstate(Type
), Type
, Value
);
2670 if (Sampler
>= WINED3DVERTEXTEXTURESAMPLER0
&& Sampler
<= WINED3DVERTEXTEXTURESAMPLER3
) {
2671 Sampler
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
2674 if (Sampler
>= sizeof(This
->stateBlock
->samplerState
)/sizeof(This
->stateBlock
->samplerState
[0])) {
2675 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler
);
2676 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
2679 * SetSampler is designed to allow for more than the standard up to 8 textures
2680 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2681 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2683 * http://developer.nvidia.com/object/General_FAQ.html#t6
2685 * There are two new settings for GForce
2687 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2688 * and the texture one:
2689 * GL_MAX_TEXTURE_COORDS_ARB.
2690 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2693 oldValue
= This
->stateBlock
->samplerState
[Sampler
][Type
];
2694 This
->updateStateBlock
->samplerState
[Sampler
][Type
] = Value
;
2695 This
->updateStateBlock
->changed
.samplerState
[Sampler
] |= 1 << Type
;
2697 /* Handle recording of state blocks */
2698 if (This
->isRecordingState
) {
2699 TRACE("Recording... not performing anything\n");
2703 if(oldValue
== Value
) {
2704 TRACE("Application is setting the old value over, nothing to do\n");
2708 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(Sampler
));
2713 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD
* Value
) {
2714 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2716 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2717 This
, Sampler
, debug_d3dsamplerstate(Type
), Type
);
2719 if (Sampler
>= WINED3DVERTEXTEXTURESAMPLER0
&& Sampler
<= WINED3DVERTEXTEXTURESAMPLER3
) {
2720 Sampler
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
2723 if (Sampler
>= sizeof(This
->stateBlock
->samplerState
)/sizeof(This
->stateBlock
->samplerState
[0])) {
2724 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler
);
2725 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
2727 *Value
= This
->stateBlock
->samplerState
[Sampler
][Type
];
2728 TRACE("(%p) : Returning %#x\n", This
, *Value
);
2733 static HRESULT WINAPI
IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice
*iface
, CONST RECT
* pRect
) {
2734 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2736 This
->updateStateBlock
->changed
.scissorRect
= TRUE
;
2737 if(EqualRect(&This
->updateStateBlock
->scissorRect
, pRect
)) {
2738 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2741 CopyRect(&This
->updateStateBlock
->scissorRect
, pRect
);
2743 if(This
->isRecordingState
) {
2744 TRACE("Recording... not performing anything\n");
2748 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SCISSORRECT
);
2753 static HRESULT WINAPI
IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice
*iface
, RECT
* pRect
) {
2754 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2756 *pRect
= This
->updateStateBlock
->scissorRect
;
2757 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This
, pRect
->left
, pRect
->top
, pRect
->right
, pRect
->bottom
);
2761 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
* pDecl
) {
2762 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2763 IWineD3DVertexDeclaration
*oldDecl
= This
->updateStateBlock
->vertexDecl
;
2765 TRACE("(%p) : pDecl=%p\n", This
, pDecl
);
2767 if (pDecl
) IWineD3DVertexDeclaration_AddRef(pDecl
);
2768 if (oldDecl
) IWineD3DVertexDeclaration_Release(oldDecl
);
2770 This
->updateStateBlock
->vertexDecl
= pDecl
;
2771 This
->updateStateBlock
->changed
.vertexDecl
= TRUE
;
2773 if (This
->isRecordingState
) {
2774 TRACE("Recording... not performing anything\n");
2776 } else if(pDecl
== oldDecl
) {
2777 /* Checked after the assignment to allow proper stateblock recording */
2778 TRACE("Application is setting the old declaration over, nothing to do\n");
2782 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
2786 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppDecl
) {
2787 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2789 TRACE("(%p) : ppDecl=%p\n", This
, ppDecl
);
2791 *ppDecl
= This
->stateBlock
->vertexDecl
;
2792 if (NULL
!= *ppDecl
) IWineD3DVertexDeclaration_AddRef(*ppDecl
);
2796 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
* pShader
) {
2797 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2798 IWineD3DVertexShader
* oldShader
= This
->updateStateBlock
->vertexShader
;
2800 This
->updateStateBlock
->vertexShader
= pShader
;
2801 This
->updateStateBlock
->changed
.vertexShader
= TRUE
;
2803 if (This
->isRecordingState
) {
2804 if(pShader
) IWineD3DVertexShader_AddRef(pShader
);
2805 if(oldShader
) IWineD3DVertexShader_Release(oldShader
);
2806 TRACE("Recording... not performing anything\n");
2808 } else if(oldShader
== pShader
) {
2809 /* Checked here to allow proper stateblock recording */
2810 TRACE("App is setting the old shader over, nothing to do\n");
2814 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
2815 if(pShader
) IWineD3DVertexShader_AddRef(pShader
);
2816 if(oldShader
) IWineD3DVertexShader_Release(oldShader
);
2818 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VSHADER
);
2823 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
** ppShader
) {
2824 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2826 if (NULL
== ppShader
) {
2827 return WINED3DERR_INVALIDCALL
;
2829 *ppShader
= This
->stateBlock
->vertexShader
;
2830 if( NULL
!= *ppShader
)
2831 IWineD3DVertexShader_AddRef(*ppShader
);
2833 TRACE("(%p) : returning %p\n", This
, *ppShader
);
2837 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantB(
2838 IWineD3DDevice
*iface
,
2840 CONST BOOL
*srcData
,
2843 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2844 unsigned int i
, cnt
= min(count
, MAX_CONST_B
- start
);
2846 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2847 iface
, srcData
, start
, count
);
2849 if (!srcData
|| start
>= MAX_CONST_B
) return WINED3DERR_INVALIDCALL
;
2851 memcpy(&This
->updateStateBlock
->vertexShaderConstantB
[start
], srcData
, cnt
* sizeof(BOOL
));
2852 for (i
= 0; i
< cnt
; i
++)
2853 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
2855 for (i
= start
; i
< cnt
+ start
; ++i
) {
2856 This
->updateStateBlock
->changed
.vertexShaderConstantsB
|= (1 << i
);
2859 if (!This
->isRecordingState
) IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
2864 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantB(
2865 IWineD3DDevice
*iface
,
2870 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2871 int cnt
= min(count
, MAX_CONST_B
- start
);
2873 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2874 iface
, dstData
, start
, count
);
2876 if (dstData
== NULL
|| cnt
< 0)
2877 return WINED3DERR_INVALIDCALL
;
2879 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantB
[start
], cnt
* sizeof(BOOL
));
2883 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantI(
2884 IWineD3DDevice
*iface
,
2889 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2890 unsigned int i
, cnt
= min(count
, MAX_CONST_I
- start
);
2892 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2893 iface
, srcData
, start
, count
);
2895 if (!srcData
|| start
>= MAX_CONST_I
) return WINED3DERR_INVALIDCALL
;
2897 memcpy(&This
->updateStateBlock
->vertexShaderConstantI
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
2898 for (i
= 0; i
< cnt
; i
++)
2899 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
2900 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
2902 for (i
= start
; i
< cnt
+ start
; ++i
) {
2903 This
->updateStateBlock
->changed
.vertexShaderConstantsI
|= (1 << i
);
2906 if (!This
->isRecordingState
) IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
2911 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantI(
2912 IWineD3DDevice
*iface
,
2917 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2918 int cnt
= min(count
, MAX_CONST_I
- start
);
2920 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2921 iface
, dstData
, start
, count
);
2923 if (dstData
== NULL
|| ((signed int) MAX_CONST_I
- (signed int) start
) <= (signed int) 0)
2924 return WINED3DERR_INVALIDCALL
;
2926 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantI
[start
* 4], cnt
* sizeof(int) * 4);
2930 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantF(
2931 IWineD3DDevice
*iface
,
2933 CONST
float *srcData
,
2936 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2939 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2940 iface
, srcData
, start
, count
);
2942 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
2943 if (srcData
== NULL
|| start
+ count
> This
->d3d_vshader_constantF
|| start
> This
->d3d_vshader_constantF
)
2944 return WINED3DERR_INVALIDCALL
;
2946 memcpy(&This
->updateStateBlock
->vertexShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
2948 for (i
= 0; i
< count
; i
++)
2949 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
2950 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
2953 if (!This
->isRecordingState
)
2955 This
->shader_backend
->shader_update_float_vertex_constants(iface
, start
, count
);
2956 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
2959 memset(This
->updateStateBlock
->changed
.vertexShaderConstantsF
+ start
, 1,
2960 sizeof(*This
->updateStateBlock
->changed
.vertexShaderConstantsF
) * count
);
2965 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantF(
2966 IWineD3DDevice
*iface
,
2971 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2972 int cnt
= min(count
, This
->d3d_vshader_constantF
- start
);
2974 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2975 iface
, dstData
, start
, count
);
2977 if (dstData
== NULL
|| cnt
< 0)
2978 return WINED3DERR_INVALIDCALL
;
2980 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantF
[start
* 4], cnt
* sizeof(float) * 4);
2984 static inline void markTextureStagesDirty(IWineD3DDeviceImpl
*This
, DWORD stage
) {
2986 for(i
= 0; i
<= WINED3D_HIGHEST_TEXTURE_STATE
; ++i
)
2988 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, i
));
2992 static void device_map_stage(IWineD3DDeviceImpl
*This
, DWORD stage
, DWORD unit
)
2994 DWORD i
= This
->rev_tex_unit_map
[unit
];
2995 DWORD j
= This
->texUnitMap
[stage
];
2997 This
->texUnitMap
[stage
] = unit
;
2998 if (i
!= WINED3D_UNMAPPED_STAGE
&& i
!= stage
)
3000 This
->texUnitMap
[i
] = WINED3D_UNMAPPED_STAGE
;
3003 This
->rev_tex_unit_map
[unit
] = stage
;
3004 if (j
!= WINED3D_UNMAPPED_STAGE
&& j
!= unit
)
3006 This
->rev_tex_unit_map
[j
] = WINED3D_UNMAPPED_STAGE
;
3010 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl
*This
) {
3013 This
->fixed_function_usage_map
= 0;
3014 for (i
= 0; i
< MAX_TEXTURES
; ++i
) {
3015 WINED3DTEXTUREOP color_op
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLOROP
];
3016 WINED3DTEXTUREOP alpha_op
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAOP
];
3017 DWORD color_arg1
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG1
] & WINED3DTA_SELECTMASK
;
3018 DWORD color_arg2
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG2
] & WINED3DTA_SELECTMASK
;
3019 DWORD color_arg3
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG0
] & WINED3DTA_SELECTMASK
;
3020 DWORD alpha_arg1
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG1
] & WINED3DTA_SELECTMASK
;
3021 DWORD alpha_arg2
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG2
] & WINED3DTA_SELECTMASK
;
3022 DWORD alpha_arg3
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG0
] & WINED3DTA_SELECTMASK
;
3024 if (color_op
== WINED3DTOP_DISABLE
) {
3025 /* Not used, and disable higher stages */
3029 if (((color_arg1
== WINED3DTA_TEXTURE
) && color_op
!= WINED3DTOP_SELECTARG2
)
3030 || ((color_arg2
== WINED3DTA_TEXTURE
) && color_op
!= WINED3DTOP_SELECTARG1
)
3031 || ((color_arg3
== WINED3DTA_TEXTURE
) && (color_op
== WINED3DTOP_MULTIPLYADD
|| color_op
== WINED3DTOP_LERP
))
3032 || ((alpha_arg1
== WINED3DTA_TEXTURE
) && alpha_op
!= WINED3DTOP_SELECTARG2
)
3033 || ((alpha_arg2
== WINED3DTA_TEXTURE
) && alpha_op
!= WINED3DTOP_SELECTARG1
)
3034 || ((alpha_arg3
== WINED3DTA_TEXTURE
) && (alpha_op
== WINED3DTOP_MULTIPLYADD
|| alpha_op
== WINED3DTOP_LERP
))) {
3035 This
->fixed_function_usage_map
|= (1 << i
);
3038 if ((color_op
== WINED3DTOP_BUMPENVMAP
|| color_op
== WINED3DTOP_BUMPENVMAPLUMINANCE
) && i
< MAX_TEXTURES
- 1) {
3039 This
->fixed_function_usage_map
|= (1 << (i
+ 1));
3044 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl
*This
) {
3045 unsigned int i
, tex
;
3048 device_update_fixed_function_usage_map(This
);
3049 ffu_map
= This
->fixed_function_usage_map
;
3051 if (This
->max_ffp_textures
== This
->max_ffp_texture_stages
||
3052 This
->stateBlock
->lowest_disabled_stage
<= This
->max_ffp_textures
) {
3053 for (i
= 0; ffu_map
; ffu_map
>>= 1, ++i
)
3055 if (!(ffu_map
& 1)) continue;
3057 if (This
->texUnitMap
[i
] != i
) {
3058 device_map_stage(This
, i
, i
);
3059 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3060 markTextureStagesDirty(This
, i
);
3066 /* Now work out the mapping */
3068 for (i
= 0; ffu_map
; ffu_map
>>= 1, ++i
)
3070 if (!(ffu_map
& 1)) continue;
3072 if (This
->texUnitMap
[i
] != tex
) {
3073 device_map_stage(This
, i
, tex
);
3074 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3075 markTextureStagesDirty(This
, i
);
3082 static void device_map_psamplers(IWineD3DDeviceImpl
*This
) {
3083 const WINED3DSAMPLER_TEXTURE_TYPE
*sampler_type
=
3084 ((IWineD3DPixelShaderImpl
*)This
->stateBlock
->pixelShader
)->baseShader
.reg_maps
.sampler_type
;
3087 for (i
= 0; i
< MAX_FRAGMENT_SAMPLERS
; ++i
) {
3088 if (sampler_type
[i
] && This
->texUnitMap
[i
] != i
)
3090 device_map_stage(This
, i
, i
);
3091 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3092 if (i
< MAX_TEXTURES
) {
3093 markTextureStagesDirty(This
, i
);
3099 static BOOL
device_unit_free_for_vs(IWineD3DDeviceImpl
*This
, const DWORD
*pshader_sampler_tokens
,
3100 const DWORD
*vshader_sampler_tokens
, DWORD unit
)
3102 DWORD current_mapping
= This
->rev_tex_unit_map
[unit
];
3104 /* Not currently used */
3105 if (current_mapping
== WINED3D_UNMAPPED_STAGE
) return TRUE
;
3107 if (current_mapping
< MAX_FRAGMENT_SAMPLERS
) {
3108 /* Used by a fragment sampler */
3110 if (!pshader_sampler_tokens
) {
3111 /* No pixel shader, check fixed function */
3112 return current_mapping
>= MAX_TEXTURES
|| !(This
->fixed_function_usage_map
& (1 << current_mapping
));
3115 /* Pixel shader, check the shader's sampler map */
3116 return !pshader_sampler_tokens
[current_mapping
];
3119 /* Used by a vertex sampler */
3120 return !vshader_sampler_tokens
[current_mapping
- MAX_FRAGMENT_SAMPLERS
];
3123 static void device_map_vsamplers(IWineD3DDeviceImpl
*This
, BOOL ps
) {
3124 const WINED3DSAMPLER_TEXTURE_TYPE
*vshader_sampler_type
=
3125 ((IWineD3DVertexShaderImpl
*)This
->stateBlock
->vertexShader
)->baseShader
.reg_maps
.sampler_type
;
3126 const WINED3DSAMPLER_TEXTURE_TYPE
*pshader_sampler_type
= NULL
;
3127 int start
= min(MAX_COMBINED_SAMPLERS
, This
->adapter
->gl_info
.limits
.combined_samplers
) - 1;
3131 IWineD3DPixelShaderImpl
*pshader
= (IWineD3DPixelShaderImpl
*)This
->stateBlock
->pixelShader
;
3133 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3134 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3135 pshader_sampler_type
= pshader
->baseShader
.reg_maps
.sampler_type
;
3138 for (i
= 0; i
< MAX_VERTEX_SAMPLERS
; ++i
) {
3139 DWORD vsampler_idx
= i
+ MAX_FRAGMENT_SAMPLERS
;
3140 if (vshader_sampler_type
[i
])
3142 if (This
->texUnitMap
[vsampler_idx
] != WINED3D_UNMAPPED_STAGE
)
3144 /* Already mapped somewhere */
3148 while (start
>= 0) {
3149 if (device_unit_free_for_vs(This
, pshader_sampler_type
, vshader_sampler_type
, start
))
3151 device_map_stage(This
, vsampler_idx
, start
);
3152 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(vsampler_idx
));
3164 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl
*This
) {
3165 BOOL vs
= use_vs(This
->stateBlock
);
3166 BOOL ps
= use_ps(This
->stateBlock
);
3169 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3170 * that would be really messy and require shader recompilation
3171 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3172 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3175 device_map_psamplers(This
);
3177 device_map_fixed_function_samplers(This
);
3181 device_map_vsamplers(This
, ps
);
3185 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
*pShader
) {
3186 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3187 IWineD3DPixelShader
*oldShader
= This
->updateStateBlock
->pixelShader
;
3188 This
->updateStateBlock
->pixelShader
= pShader
;
3189 This
->updateStateBlock
->changed
.pixelShader
= TRUE
;
3191 /* Handle recording of state blocks */
3192 if (This
->isRecordingState
) {
3193 TRACE("Recording... not performing anything\n");
3196 if (This
->isRecordingState
) {
3197 TRACE("Recording... not performing anything\n");
3198 if(pShader
) IWineD3DPixelShader_AddRef(pShader
);
3199 if(oldShader
) IWineD3DPixelShader_Release(oldShader
);
3203 if(pShader
== oldShader
) {
3204 TRACE("App is setting the old pixel shader over, nothing to do\n");
3208 if(pShader
) IWineD3DPixelShader_AddRef(pShader
);
3209 if(oldShader
) IWineD3DPixelShader_Release(oldShader
);
3211 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
3212 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADER
);
3217 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
**ppShader
) {
3218 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3220 if (NULL
== ppShader
) {
3221 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This
);
3222 return WINED3DERR_INVALIDCALL
;
3225 *ppShader
= This
->stateBlock
->pixelShader
;
3226 if (NULL
!= *ppShader
) {
3227 IWineD3DPixelShader_AddRef(*ppShader
);
3229 TRACE("(%p) : returning %p\n", This
, *ppShader
);
3233 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantB(
3234 IWineD3DDevice
*iface
,
3236 CONST BOOL
*srcData
,
3239 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3240 unsigned int i
, cnt
= min(count
, MAX_CONST_B
- start
);
3242 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3243 iface
, srcData
, start
, count
);
3245 if (!srcData
|| start
>= MAX_CONST_B
) return WINED3DERR_INVALIDCALL
;
3247 memcpy(&This
->updateStateBlock
->pixelShaderConstantB
[start
], srcData
, cnt
* sizeof(BOOL
));
3248 for (i
= 0; i
< cnt
; i
++)
3249 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
3251 for (i
= start
; i
< cnt
+ start
; ++i
) {
3252 This
->updateStateBlock
->changed
.pixelShaderConstantsB
|= (1 << i
);
3255 if (!This
->isRecordingState
) IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3260 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantB(
3261 IWineD3DDevice
*iface
,
3266 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3267 int cnt
= min(count
, MAX_CONST_B
- start
);
3269 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3270 iface
, dstData
, start
, count
);
3272 if (dstData
== NULL
|| cnt
< 0)
3273 return WINED3DERR_INVALIDCALL
;
3275 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantB
[start
], cnt
* sizeof(BOOL
));
3279 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantI(
3280 IWineD3DDevice
*iface
,
3285 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3286 unsigned int i
, cnt
= min(count
, MAX_CONST_I
- start
);
3288 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3289 iface
, srcData
, start
, count
);
3291 if (!srcData
|| start
>= MAX_CONST_I
) return WINED3DERR_INVALIDCALL
;
3293 memcpy(&This
->updateStateBlock
->pixelShaderConstantI
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
3294 for (i
= 0; i
< cnt
; i
++)
3295 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
3296 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3298 for (i
= start
; i
< cnt
+ start
; ++i
) {
3299 This
->updateStateBlock
->changed
.pixelShaderConstantsI
|= (1 << i
);
3302 if (!This
->isRecordingState
) IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3307 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantI(
3308 IWineD3DDevice
*iface
,
3313 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3314 int cnt
= min(count
, MAX_CONST_I
- start
);
3316 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3317 iface
, dstData
, start
, count
);
3319 if (dstData
== NULL
|| cnt
< 0)
3320 return WINED3DERR_INVALIDCALL
;
3322 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantI
[start
* 4], cnt
* sizeof(int) * 4);
3326 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantF(
3327 IWineD3DDevice
*iface
,
3329 CONST
float *srcData
,
3332 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3335 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3336 iface
, srcData
, start
, count
);
3338 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3339 if (srcData
== NULL
|| start
+ count
> This
->d3d_pshader_constantF
|| start
> This
->d3d_pshader_constantF
)
3340 return WINED3DERR_INVALIDCALL
;
3342 memcpy(&This
->updateStateBlock
->pixelShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
3344 for (i
= 0; i
< count
; i
++)
3345 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
3346 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3349 if (!This
->isRecordingState
)
3351 This
->shader_backend
->shader_update_float_pixel_constants(iface
, start
, count
);
3352 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3355 memset(This
->updateStateBlock
->changed
.pixelShaderConstantsF
+ start
, 1,
3356 sizeof(*This
->updateStateBlock
->changed
.pixelShaderConstantsF
) * count
);
3361 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantF(
3362 IWineD3DDevice
*iface
,
3367 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3368 int cnt
= min(count
, This
->d3d_pshader_constantF
- start
);
3370 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3371 iface
, dstData
, start
, count
);
3373 if (dstData
== NULL
|| cnt
< 0)
3374 return WINED3DERR_INVALIDCALL
;
3376 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantF
[start
* 4], cnt
* sizeof(float) * 4);
3380 /* Context activation is done by the caller. */
3381 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3382 static HRESULT
process_vertices_strided(IWineD3DDeviceImpl
*This
, DWORD dwDestIndex
, DWORD dwCount
,
3383 const struct wined3d_stream_info
*stream_info
, struct wined3d_buffer
*dest
, DWORD dwFlags
,
3386 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
3387 char *dest_ptr
, *dest_conv
= NULL
, *dest_conv_addr
= NULL
;
3390 WINED3DMATRIX mat
, proj_mat
, view_mat
, world_mat
;
3394 if (stream_info
->use_map
& (1 << WINED3D_FFP_NORMAL
))
3396 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3399 if (!(stream_info
->use_map
& (1 << WINED3D_FFP_POSITION
)))
3401 ERR("Source has no position mask\n");
3402 return WINED3DERR_INVALIDCALL
;
3405 /* We might access VBOs from this code, so hold the lock */
3408 if (dest
->resource
.allocatedMemory
== NULL
) {
3409 buffer_get_sysmem(dest
);
3412 /* Get a pointer into the destination vbo(create one if none exists) and
3413 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3415 if (!dest
->buffer_object
&& gl_info
->supported
[ARB_VERTEX_BUFFER_OBJECT
])
3417 dest
->flags
|= WINED3D_BUFFER_CREATEBO
;
3418 IWineD3DBuffer_PreLoad((IWineD3DBuffer
*)dest
);
3421 if (dest
->buffer_object
)
3423 unsigned char extrabytes
= 0;
3424 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3425 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3426 * this may write 4 extra bytes beyond the area that should be written
3428 if(DestFVF
== WINED3DFVF_XYZ
) extrabytes
= 4;
3429 dest_conv_addr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwCount
* get_flexible_vertex_size(DestFVF
) + extrabytes
);
3430 if(!dest_conv_addr
) {
3431 ERR("Out of memory\n");
3432 /* Continue without storing converted vertices */
3434 dest_conv
= dest_conv_addr
;
3438 * a) WINED3DRS_CLIPPING is enabled
3439 * b) WINED3DVOP_CLIP is passed
3441 if(This
->stateBlock
->renderState
[WINED3DRS_CLIPPING
]) {
3442 static BOOL warned
= FALSE
;
3444 * The clipping code is not quite correct. Some things need
3445 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3446 * so disable clipping for now.
3447 * (The graphics in Half-Life are broken, and my processvertices
3448 * test crashes with IDirect3DDevice3)
3454 FIXME("Clipping is broken and disabled for now\n");
3456 } else doClip
= FALSE
;
3457 dest_ptr
= ((char *) buffer_get_sysmem(dest
)) + dwDestIndex
* get_flexible_vertex_size(DestFVF
);
3459 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
3462 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
3463 WINED3DTS_PROJECTION
,
3465 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
3466 WINED3DTS_WORLDMATRIX(0),
3469 TRACE("View mat:\n");
3470 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
);
3471 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
);
3472 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
);
3473 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
);
3475 TRACE("Proj mat:\n");
3476 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
);
3477 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
);
3478 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
);
3479 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
);
3481 TRACE("World mat:\n");
3482 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
);
3483 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
);
3484 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
);
3485 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
);
3487 /* Get the viewport */
3488 IWineD3DDevice_GetViewport( (IWineD3DDevice
*) This
, &vp
);
3489 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3490 vp
.X
, vp
.Y
, vp
.Width
, vp
.Height
, vp
.MinZ
, vp
.MaxZ
);
3492 multiply_matrix(&mat
,&view_mat
,&world_mat
);
3493 multiply_matrix(&mat
,&proj_mat
,&mat
);
3495 numTextures
= (DestFVF
& WINED3DFVF_TEXCOUNT_MASK
) >> WINED3DFVF_TEXCOUNT_SHIFT
;
3497 for (i
= 0; i
< dwCount
; i
+= 1) {
3498 unsigned int tex_index
;
3500 if ( ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZ
) ||
3501 ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) ) {
3502 /* The position first */
3503 const struct wined3d_stream_info_element
*element
= &stream_info
->elements
[WINED3D_FFP_POSITION
];
3504 const float *p
= (const float *)(element
->data
+ i
* element
->stride
);
3506 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p
[0], p
[1], p
[2]);
3508 /* Multiplication with world, view and projection matrix */
3509 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
);
3510 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
);
3511 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
);
3512 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
);
3514 TRACE("x=%f y=%f z=%f rhw=%f\n", x
, y
, z
, rhw
);
3516 /* WARNING: The following things are taken from d3d7 and were not yet checked
3517 * against d3d8 or d3d9!
3520 /* Clipping conditions: From msdn
3522 * A vertex is clipped if it does not match the following requirements
3526 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3528 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3529 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3534 ( (-rhw
-eps
< x
) && (-rhw
-eps
< y
) && ( -eps
< z
) &&
3535 (x
<= rhw
+ eps
) && (y
<= rhw
+ eps
) && (z
<= rhw
+ eps
) &&
3538 /* "Normal" viewport transformation (not clipped)
3539 * 1) The values are divided by rhw
3540 * 2) The y axis is negative, so multiply it with -1
3541 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3542 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3543 * 4) Multiply x with Width/2 and add Width/2
3544 * 5) The same for the height
3545 * 6) Add the viewpoint X and Y to the 2D coordinates and
3546 * The minimum Z value to z
3547 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3549 * Well, basically it's simply a linear transformation into viewport
3561 z
*= vp
.MaxZ
- vp
.MinZ
;
3563 x
+= vp
.Width
/ 2 + vp
.X
;
3564 y
+= vp
.Height
/ 2 + vp
.Y
;
3569 /* That vertex got clipped
3570 * Contrary to OpenGL it is not dropped completely, it just
3571 * undergoes a different calculation.
3573 TRACE("Vertex got clipped\n");
3580 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3581 * outside of the main vertex buffer memory. That needs some more
3586 TRACE("Writing (%f %f %f) %f\n", x
, y
, z
, rhw
);
3589 ( (float *) dest_ptr
)[0] = x
;
3590 ( (float *) dest_ptr
)[1] = y
;
3591 ( (float *) dest_ptr
)[2] = z
;
3592 ( (float *) dest_ptr
)[3] = rhw
; /* SIC, see ddraw test! */
3594 dest_ptr
+= 3 * sizeof(float);
3596 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
3597 dest_ptr
+= sizeof(float);
3602 ( (float *) dest_conv
)[0] = x
* w
;
3603 ( (float *) dest_conv
)[1] = y
* w
;
3604 ( (float *) dest_conv
)[2] = z
* w
;
3605 ( (float *) dest_conv
)[3] = w
;
3607 dest_conv
+= 3 * sizeof(float);
3609 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
3610 dest_conv
+= sizeof(float);
3614 if (DestFVF
& WINED3DFVF_PSIZE
) {
3615 dest_ptr
+= sizeof(DWORD
);
3616 if(dest_conv
) dest_conv
+= sizeof(DWORD
);
3618 if (DestFVF
& WINED3DFVF_NORMAL
) {
3619 const struct wined3d_stream_info_element
*element
= &stream_info
->elements
[WINED3D_FFP_NORMAL
];
3620 const float *normal
= (const float *)(element
->data
+ i
* element
->stride
);
3621 /* AFAIK this should go into the lighting information */
3622 FIXME("Didn't expect the destination to have a normal\n");
3623 copy_and_next(dest_ptr
, normal
, 3 * sizeof(float));
3625 copy_and_next(dest_conv
, normal
, 3 * sizeof(float));
3629 if (DestFVF
& WINED3DFVF_DIFFUSE
) {
3630 const struct wined3d_stream_info_element
*element
= &stream_info
->elements
[WINED3D_FFP_DIFFUSE
];
3631 const DWORD
*color_d
= (const DWORD
*)(element
->data
+ i
* element
->stride
);
3632 if (!(stream_info
->use_map
& (1 << WINED3D_FFP_DIFFUSE
)))
3634 static BOOL warned
= FALSE
;
3637 ERR("No diffuse color in source, but destination has one\n");
3641 *( (DWORD
*) dest_ptr
) = 0xffffffff;
3642 dest_ptr
+= sizeof(DWORD
);
3645 *( (DWORD
*) dest_conv
) = 0xffffffff;
3646 dest_conv
+= sizeof(DWORD
);
3650 copy_and_next(dest_ptr
, color_d
, sizeof(DWORD
));
3652 *( (DWORD
*) dest_conv
) = (*color_d
& 0xff00ff00) ; /* Alpha + green */
3653 *( (DWORD
*) dest_conv
) |= (*color_d
& 0x00ff0000) >> 16; /* Red */
3654 *( (DWORD
*) dest_conv
) |= (*color_d
& 0xff0000ff) << 16; /* Blue */
3655 dest_conv
+= sizeof(DWORD
);
3660 if (DestFVF
& WINED3DFVF_SPECULAR
)
3662 /* What's the color value in the feedback buffer? */
3663 const struct wined3d_stream_info_element
*element
= &stream_info
->elements
[WINED3D_FFP_SPECULAR
];
3664 const DWORD
*color_s
= (const DWORD
*)(element
->data
+ i
* element
->stride
);
3665 if (!(stream_info
->use_map
& (1 << WINED3D_FFP_SPECULAR
)))
3667 static BOOL warned
= FALSE
;
3670 ERR("No specular color in source, but destination has one\n");
3674 *( (DWORD
*) dest_ptr
) = 0xFF000000;
3675 dest_ptr
+= sizeof(DWORD
);
3678 *( (DWORD
*) dest_conv
) = 0xFF000000;
3679 dest_conv
+= sizeof(DWORD
);
3683 copy_and_next(dest_ptr
, color_s
, sizeof(DWORD
));
3685 *( (DWORD
*) dest_conv
) = (*color_s
& 0xff00ff00) ; /* Alpha + green */
3686 *( (DWORD
*) dest_conv
) |= (*color_s
& 0x00ff0000) >> 16; /* Red */
3687 *( (DWORD
*) dest_conv
) |= (*color_s
& 0xff0000ff) << 16; /* Blue */
3688 dest_conv
+= sizeof(DWORD
);
3693 for (tex_index
= 0; tex_index
< numTextures
; tex_index
++) {
3694 const struct wined3d_stream_info_element
*element
= &stream_info
->elements
[WINED3D_FFP_TEXCOORD0
+ tex_index
];
3695 const float *tex_coord
= (const float *)(element
->data
+ i
* element
->stride
);
3696 if (!(stream_info
->use_map
& (1 << (WINED3D_FFP_TEXCOORD0
+ tex_index
))))
3698 ERR("No source texture, but destination requests one\n");
3699 dest_ptr
+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
3700 if(dest_conv
) dest_conv
+= GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
3703 copy_and_next(dest_ptr
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
3705 copy_and_next(dest_conv
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
3712 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, dest
->buffer_object
));
3713 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3714 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB
, dwDestIndex
* get_flexible_vertex_size(DestFVF
),
3715 dwCount
* get_flexible_vertex_size(DestFVF
),
3717 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3718 HeapFree(GetProcessHeap(), 0, dest_conv_addr
);
3725 #undef copy_and_next
3727 static HRESULT WINAPI
IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice
*iface
, UINT SrcStartIndex
, UINT DestIndex
,
3728 UINT VertexCount
, IWineD3DBuffer
*pDestBuffer
, IWineD3DVertexDeclaration
*pVertexDecl
, DWORD Flags
,
3731 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3732 struct wined3d_stream_info stream_info
;
3733 struct wined3d_context
*context
;
3734 BOOL vbo
= FALSE
, streamWasUP
= This
->stateBlock
->streamIsUP
;
3737 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This
, SrcStartIndex
, DestIndex
, VertexCount
, pDestBuffer
, pVertexDecl
, Flags
);
3740 ERR("Output vertex declaration not implemented yet\n");
3743 /* Need any context to write to the vbo. */
3744 context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
3746 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3747 * control the streamIsUP flag, thus restore it afterwards.
3749 This
->stateBlock
->streamIsUP
= FALSE
;
3750 device_stream_info_from_declaration(This
, FALSE
, &stream_info
, &vbo
);
3751 This
->stateBlock
->streamIsUP
= streamWasUP
;
3753 if(vbo
|| SrcStartIndex
) {
3755 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
3756 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
3758 * Also get the start index in, but only loop over all elements if there's something to add at all.
3760 for (i
= 0; i
< (sizeof(stream_info
.elements
) / sizeof(*stream_info
.elements
)); ++i
)
3762 struct wined3d_stream_info_element
*e
;
3764 if (!(stream_info
.use_map
& (1 << i
))) continue;
3766 e
= &stream_info
.elements
[i
];
3767 if (e
->buffer_object
)
3769 struct wined3d_buffer
*vb
= (struct wined3d_buffer
*)This
->stateBlock
->streamSource
[e
->stream_idx
];
3770 e
->buffer_object
= 0;
3771 e
->data
= (BYTE
*)((unsigned long)e
->data
+ (unsigned long)buffer_get_sysmem(vb
));
3773 GL_EXTCALL(glDeleteBuffersARB(1, &vb
->buffer_object
));
3774 vb
->buffer_object
= 0;
3777 if (e
->data
) e
->data
+= e
->stride
* SrcStartIndex
;
3781 hr
= process_vertices_strided(This
, DestIndex
, VertexCount
, &stream_info
,
3782 (struct wined3d_buffer
*)pDestBuffer
, Flags
, DestFVF
);
3784 context_release(context
);
3790 * Get / Set Texture Stage States
3791 * TODO: Verify against dx9 definitions
3793 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD Value
) {
3794 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3795 DWORD oldValue
= This
->updateStateBlock
->textureState
[Stage
][Type
];
3797 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This
, Stage
, debug_d3dtexturestate(Type
), Type
, Value
);
3799 if (Stage
>= MAX_TEXTURES
) {
3800 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage
, MAX_TEXTURES
- 1);
3804 This
->updateStateBlock
->changed
.textureState
[Stage
] |= 1 << Type
;
3805 This
->updateStateBlock
->textureState
[Stage
][Type
] = Value
;
3807 if (This
->isRecordingState
) {
3808 TRACE("Recording... not performing anything\n");
3812 /* Checked after the assignments to allow proper stateblock recording */
3813 if(oldValue
== Value
) {
3814 TRACE("App is setting the old value over, nothing to do\n");
3818 if(Stage
> This
->stateBlock
->lowest_disabled_stage
&&
3819 This
->StateTable
[STATE_TEXTURESTAGE(0, Type
)].representative
== STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP
)) {
3820 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3821 * Changes in other states are important on disabled stages too
3826 if(Type
== WINED3DTSS_COLOROP
) {
3829 if(Value
== WINED3DTOP_DISABLE
&& oldValue
!= WINED3DTOP_DISABLE
) {
3830 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3831 * they have to be disabled
3833 * The current stage is dirtified below.
3835 for(i
= Stage
+ 1; i
< This
->stateBlock
->lowest_disabled_stage
; i
++) {
3836 TRACE("Additionally dirtifying stage %u\n", i
);
3837 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
3839 This
->stateBlock
->lowest_disabled_stage
= Stage
;
3840 TRACE("New lowest disabled: %u\n", Stage
);
3841 } else if(Value
!= WINED3DTOP_DISABLE
&& oldValue
== WINED3DTOP_DISABLE
) {
3842 /* Previously disabled stage enabled. Stages above it may need enabling
3843 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3844 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3846 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3849 for (i
= Stage
+ 1; i
< This
->adapter
->gl_info
.limits
.texture_stages
; ++i
)
3851 if(This
->updateStateBlock
->textureState
[i
][WINED3DTSS_COLOROP
] == WINED3DTOP_DISABLE
) {
3854 TRACE("Additionally dirtifying stage %u due to enable\n", i
);
3855 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
3857 This
->stateBlock
->lowest_disabled_stage
= i
;
3858 TRACE("New lowest disabled: %u\n", i
);
3862 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, Type
));
3867 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD
* pValue
) {
3868 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3869 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This
, Stage
, Type
, This
->updateStateBlock
->textureState
[Stage
][Type
]);
3870 *pValue
= This
->updateStateBlock
->textureState
[Stage
][Type
];
3877 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTexture(IWineD3DDevice
*iface
,
3878 DWORD stage
, IWineD3DBaseTexture
*texture
)
3880 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3881 IWineD3DBaseTexture
*prev
;
3883 TRACE("iface %p, stage %u, texture %p.\n", iface
, stage
, texture
);
3885 if (stage
>= WINED3DVERTEXTEXTURESAMPLER0
&& stage
<= WINED3DVERTEXTEXTURESAMPLER3
)
3886 stage
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
3888 /* Windows accepts overflowing this array... we do not. */
3889 if (stage
>= sizeof(This
->stateBlock
->textures
) / sizeof(*This
->stateBlock
->textures
))
3891 WARN("Ignoring invalid stage %u.\n", stage
);
3895 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
3896 if (texture
&& ((IWineD3DTextureImpl
*)texture
)->resource
.pool
== WINED3DPOOL_SCRATCH
)
3898 WARN("Rejecting attempt to set scratch texture.\n");
3899 return WINED3DERR_INVALIDCALL
;
3902 This
->updateStateBlock
->changed
.textures
|= 1 << stage
;
3904 prev
= This
->updateStateBlock
->textures
[stage
];
3905 TRACE("Previous texture %p.\n", prev
);
3907 if (texture
== prev
)
3909 TRACE("App is setting the same texture again, nothing to do.\n");
3913 TRACE("Setting new texture to %p.\n", texture
);
3914 This
->updateStateBlock
->textures
[stage
] = texture
;
3916 if (This
->isRecordingState
)
3918 TRACE("Recording... not performing anything\n");
3920 if (texture
) IWineD3DBaseTexture_AddRef(texture
);
3921 if (prev
) IWineD3DBaseTexture_Release(prev
);
3928 IWineD3DBaseTextureImpl
*t
= (IWineD3DBaseTextureImpl
*)texture
;
3929 LONG bind_count
= InterlockedIncrement(&t
->baseTexture
.bindCount
);
3930 UINT dimensions
= IWineD3DBaseTexture_GetTextureDimensions(texture
);
3932 IWineD3DBaseTexture_AddRef(texture
);
3934 if (!prev
|| dimensions
!= IWineD3DBaseTexture_GetTextureDimensions(prev
))
3936 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADER
);
3939 if (!prev
&& stage
< MAX_TEXTURES
)
3941 /* The source arguments for color and alpha ops have different
3942 * meanings when a NULL texture is bound, so the COLOROP and
3943 * ALPHAOP have to be dirtified. */
3944 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, WINED3DTSS_COLOROP
));
3945 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, WINED3DTSS_ALPHAOP
));
3948 if (bind_count
== 1) t
->baseTexture
.sampler
= stage
;
3953 IWineD3DBaseTextureImpl
*t
= (IWineD3DBaseTextureImpl
*)prev
;
3954 LONG bind_count
= InterlockedDecrement(&t
->baseTexture
.bindCount
);
3956 IWineD3DBaseTexture_Release(prev
);
3958 if (!texture
&& stage
< MAX_TEXTURES
)
3960 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, WINED3DTSS_COLOROP
));
3961 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, WINED3DTSS_ALPHAOP
));
3964 if (bind_count
&& t
->baseTexture
.sampler
== stage
)
3968 /* Search for other stages the texture is bound to. Shouldn't
3969 * happen if applications bind textures to a single stage only. */
3970 TRACE("Searching for other stages the texture is bound to.\n");
3971 for (i
= 0; i
< MAX_COMBINED_SAMPLERS
; ++i
)
3973 if (This
->updateStateBlock
->textures
[i
] == prev
)
3975 TRACE("Texture is also bound to stage %u.\n", i
);
3976 t
->baseTexture
.sampler
= i
;
3983 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(stage
));
3988 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTexture(IWineD3DDevice
*iface
, DWORD Stage
, IWineD3DBaseTexture
** ppTexture
) {
3989 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3991 TRACE("(%p) : Stage %#x, ppTexture %p\n", This
, Stage
, ppTexture
);
3993 if (Stage
>= WINED3DVERTEXTEXTURESAMPLER0
&& Stage
<= WINED3DVERTEXTEXTURESAMPLER3
) {
3994 Stage
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
3997 if (Stage
>= sizeof(This
->stateBlock
->textures
)/sizeof(This
->stateBlock
->textures
[0])) {
3998 ERR("Current stage overflows textures array (stage %d)\n", Stage
);
3999 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
4002 *ppTexture
=This
->stateBlock
->textures
[Stage
];
4004 IWineD3DBaseTexture_AddRef(*ppTexture
);
4006 TRACE("(%p) : Returning %p\n", This
, *ppTexture
);
4014 static HRESULT WINAPI
IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice
*iface
, UINT iSwapChain
, UINT BackBuffer
, WINED3DBACKBUFFER_TYPE Type
,
4015 IWineD3DSurface
**ppBackBuffer
) {
4016 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4017 IWineD3DSwapChain
*swapChain
;
4020 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This
, BackBuffer
, Type
, iSwapChain
, *ppBackBuffer
);
4022 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
4023 if (hr
== WINED3D_OK
) {
4024 hr
= IWineD3DSwapChain_GetBackBuffer(swapChain
, BackBuffer
, Type
, ppBackBuffer
);
4025 IWineD3DSwapChain_Release(swapChain
);
4027 *ppBackBuffer
= NULL
;
4032 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice
*iface
, WINED3DCAPS
* pCaps
) {
4033 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4034 WARN("(%p) : stub, calling idirect3d for now\n", This
);
4035 return IWineD3D_GetDeviceCaps(This
->wined3d
, This
->adapter
->ordinal
, This
->devType
, pCaps
);
4038 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DDISPLAYMODE
* pMode
) {
4039 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4040 IWineD3DSwapChain
*swapChain
;
4043 if(iSwapChain
> 0) {
4044 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
4045 if (hr
== WINED3D_OK
) {
4046 hr
= IWineD3DSwapChain_GetDisplayMode(swapChain
, pMode
);
4047 IWineD3DSwapChain_Release(swapChain
);
4049 FIXME("(%p) Error getting display mode\n", This
);
4052 /* Don't read the real display mode,
4053 but return the stored mode instead. X11 can't change the color
4054 depth, and some apps are pretty angry if they SetDisplayMode from
4055 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4057 Also don't relay to the swapchain because with ddraw it's possible
4058 that there isn't a swapchain at all */
4059 pMode
->Width
= This
->ddraw_width
;
4060 pMode
->Height
= This
->ddraw_height
;
4061 pMode
->Format
= This
->ddraw_format
;
4062 pMode
->RefreshRate
= 0;
4070 * Stateblock related functions
4073 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice
*iface
) {
4074 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4075 IWineD3DStateBlock
*stateblock
;
4078 TRACE("(%p)\n", This
);
4080 if (This
->isRecordingState
) return WINED3DERR_INVALIDCALL
;
4082 hr
= IWineD3DDeviceImpl_CreateStateBlock(iface
, WINED3DSBT_RECORDED
, &stateblock
, NULL
);
4083 if (FAILED(hr
)) return hr
;
4085 IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
);
4086 This
->updateStateBlock
= (IWineD3DStateBlockImpl
*)stateblock
;
4087 This
->isRecordingState
= TRUE
;
4089 TRACE("(%p) recording stateblock %p\n", This
, stateblock
);
4094 static HRESULT WINAPI
IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice
*iface
, IWineD3DStateBlock
** ppStateBlock
) {
4095 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4096 IWineD3DStateBlockImpl
*object
= This
->updateStateBlock
;
4098 if (!This
->isRecordingState
) {
4099 WARN("(%p) not recording! returning error\n", This
);
4100 *ppStateBlock
= NULL
;
4101 return WINED3DERR_INVALIDCALL
;
4104 stateblock_init_contained_states(object
);
4106 *ppStateBlock
= (IWineD3DStateBlock
*) object
;
4107 This
->isRecordingState
= FALSE
;
4108 This
->updateStateBlock
= This
->stateBlock
;
4109 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
4110 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4111 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This
, *ppStateBlock
);
4116 * Scene related functions
4118 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginScene(IWineD3DDevice
*iface
) {
4119 /* At the moment we have no need for any functionality at the beginning
4121 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4122 TRACE("(%p)\n", This
);
4125 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4126 return WINED3DERR_INVALIDCALL
;
4128 This
->inScene
= TRUE
;
4132 static HRESULT WINAPI
IWineD3DDeviceImpl_EndScene(IWineD3DDevice
*iface
)
4134 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4135 struct wined3d_context
*context
;
4137 TRACE("(%p)\n", This
);
4139 if(!This
->inScene
) {
4140 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4141 return WINED3DERR_INVALIDCALL
;
4144 context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
4145 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4147 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4149 context_release(context
);
4151 This
->inScene
= FALSE
;
4155 static HRESULT WINAPI
IWineD3DDeviceImpl_Present(IWineD3DDevice
*iface
,
4156 CONST RECT
* pSourceRect
, CONST RECT
* pDestRect
,
4157 HWND hDestWindowOverride
, CONST RGNDATA
* pDirtyRegion
) {
4158 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4159 IWineD3DSwapChain
*swapChain
= NULL
;
4161 int swapchains
= IWineD3DDeviceImpl_GetNumberOfSwapChains(iface
);
4163 TRACE("(%p) Presenting the frame\n", This
);
4165 for(i
= 0 ; i
< swapchains
; i
++) {
4167 IWineD3DDeviceImpl_GetSwapChain(iface
, i
, &swapChain
);
4168 TRACE("presentinng chain %d, %p\n", i
, swapChain
);
4169 IWineD3DSwapChain_Present(swapChain
, pSourceRect
, pDestRect
, hDestWindowOverride
, pDirtyRegion
, 0);
4170 IWineD3DSwapChain_Release(swapChain
);
4176 /* Not called from the VTable (internal subroutine) */
4177 HRESULT
IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl
*This
, IWineD3DSurfaceImpl
*target
, DWORD Count
,
4178 CONST WINED3DRECT
* pRects
, DWORD Flags
, WINED3DCOLOR Color
,
4179 float Z
, DWORD Stencil
) {
4180 GLbitfield glMask
= 0;
4182 WINED3DRECT curRect
;
4184 const WINED3DVIEWPORT
*vp
= &This
->stateBlock
->viewport
;
4185 UINT drawable_width
, drawable_height
;
4186 IWineD3DSurfaceImpl
*depth_stencil
= (IWineD3DSurfaceImpl
*) This
->stencilBufferTarget
;
4187 IWineD3DSwapChainImpl
*swapchain
= NULL
;
4188 struct wined3d_context
*context
;
4190 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4191 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4192 * for the cleared parts, and the untouched parts.
4194 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4195 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4196 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4197 * checking all this if the dest surface is in the drawable anyway.
4199 if((Flags
& WINED3DCLEAR_TARGET
) && !(target
->Flags
& SFLAG_INDRAWABLE
)) {
4201 if(vp
->X
!= 0 || vp
->Y
!= 0 ||
4202 vp
->Width
< target
->currentDesc
.Width
|| vp
->Height
< target
->currentDesc
.Height
) {
4203 IWineD3DSurface_LoadLocation((IWineD3DSurface
*) target
, SFLAG_INDRAWABLE
, NULL
);
4206 if(This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
] && (
4207 This
->stateBlock
->scissorRect
.left
> 0 || This
->stateBlock
->scissorRect
.top
> 0 ||
4208 This
->stateBlock
->scissorRect
.right
< target
->currentDesc
.Width
||
4209 This
->stateBlock
->scissorRect
.bottom
< target
->currentDesc
.Height
)) {
4210 IWineD3DSurface_LoadLocation((IWineD3DSurface
*) target
, SFLAG_INDRAWABLE
, NULL
);
4213 if(Count
> 0 && pRects
&& (
4214 pRects
[0].x1
> 0 || pRects
[0].y1
> 0 ||
4215 pRects
[0].x2
< target
->currentDesc
.Width
||
4216 pRects
[0].y2
< target
->currentDesc
.Height
)) {
4217 IWineD3DSurface_LoadLocation((IWineD3DSurface
*) target
, SFLAG_INDRAWABLE
, NULL
);
4224 context
= context_acquire(This
, (IWineD3DSurface
*)target
, CTXUSAGE_CLEAR
);
4226 target
->get_drawable_size(context
, &drawable_width
, &drawable_height
);
4230 /* Only set the values up once, as they are not changing */
4231 if (Flags
& WINED3DCLEAR_STENCIL
) {
4232 glClearStencil(Stencil
);
4233 checkGLcall("glClearStencil");
4234 glMask
= glMask
| GL_STENCIL_BUFFER_BIT
;
4235 glStencilMask(0xFFFFFFFF);
4238 if (Flags
& WINED3DCLEAR_ZBUFFER
) {
4239 DWORD location
= context
->render_offscreen
? SFLAG_DS_OFFSCREEN
: SFLAG_DS_ONSCREEN
;
4240 glDepthMask(GL_TRUE
);
4242 checkGLcall("glClearDepth");
4243 glMask
= glMask
| GL_DEPTH_BUFFER_BIT
;
4244 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ZWRITEENABLE
));
4246 if (vp
->X
!= 0 || vp
->Y
!= 0 ||
4247 vp
->Width
< depth_stencil
->currentDesc
.Width
|| vp
->Height
< depth_stencil
->currentDesc
.Height
) {
4248 surface_load_ds_location(This
->stencilBufferTarget
, context
, location
);
4250 else if (This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
] && (
4251 This
->stateBlock
->scissorRect
.left
> 0 || This
->stateBlock
->scissorRect
.top
> 0 ||
4252 This
->stateBlock
->scissorRect
.right
< depth_stencil
->currentDesc
.Width
||
4253 This
->stateBlock
->scissorRect
.bottom
< depth_stencil
->currentDesc
.Height
)) {
4254 surface_load_ds_location(This
->stencilBufferTarget
, context
, location
);
4256 else if (Count
> 0 && pRects
&& (
4257 pRects
[0].x1
> 0 || pRects
[0].y1
> 0 ||
4258 pRects
[0].x2
< depth_stencil
->currentDesc
.Width
||
4259 pRects
[0].y2
< depth_stencil
->currentDesc
.Height
)) {
4260 surface_load_ds_location(This
->stencilBufferTarget
, context
, location
);
4264 if (Flags
& WINED3DCLEAR_TARGET
) {
4265 TRACE("Clearing screen with glClear to color %x\n", Color
);
4266 glClearColor(D3DCOLOR_R(Color
),
4270 checkGLcall("glClearColor");
4272 /* Clear ALL colors! */
4273 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
4274 glMask
= glMask
| GL_COLOR_BUFFER_BIT
;
4277 vp_rect
.left
= vp
->X
;
4278 vp_rect
.top
= vp
->Y
;
4279 vp_rect
.right
= vp
->X
+ vp
->Width
;
4280 vp_rect
.bottom
= vp
->Y
+ vp
->Height
;
4281 if (!(Count
> 0 && pRects
)) {
4282 if(This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
]) {
4283 IntersectRect(&vp_rect
, &vp_rect
, &This
->stateBlock
->scissorRect
);
4285 if (context
->render_offscreen
)
4287 glScissor(vp_rect
.left
, vp_rect
.top
,
4288 vp_rect
.right
- vp_rect
.left
, vp_rect
.bottom
- vp_rect
.top
);
4290 glScissor(vp_rect
.left
, drawable_height
- vp_rect
.bottom
,
4291 vp_rect
.right
- vp_rect
.left
, vp_rect
.bottom
- vp_rect
.top
);
4293 checkGLcall("glScissor");
4295 checkGLcall("glClear");
4297 /* Now process each rect in turn */
4298 for (i
= 0; i
< Count
; i
++) {
4299 /* Note gl uses lower left, width/height */
4300 IntersectRect((RECT
*)&curRect
, &vp_rect
, (const RECT
*)&pRects
[i
]);
4301 if(This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
]) {
4302 IntersectRect((RECT
*) &curRect
, (RECT
*) &curRect
, &This
->stateBlock
->scissorRect
);
4304 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This
,
4305 pRects
[i
].x1
, pRects
[i
].y1
, pRects
[i
].x2
, pRects
[i
].y2
,
4306 curRect
.x1
, (target
->currentDesc
.Height
- curRect
.y2
),
4307 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
4309 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4310 * The rectangle is not cleared, no error is returned, but further rectanlges are
4311 * still cleared if they are valid
4313 if(curRect
.x1
> curRect
.x2
|| curRect
.y1
> curRect
.y2
) {
4314 TRACE("Rectangle with negative dimensions, ignoring\n");
4318 if (context
->render_offscreen
)
4320 glScissor(curRect
.x1
, curRect
.y1
,
4321 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
4323 glScissor(curRect
.x1
, drawable_height
- curRect
.y2
,
4324 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
4326 checkGLcall("glScissor");
4329 checkGLcall("glClear");
4333 /* Restore the old values (why..?) */
4334 if (Flags
& WINED3DCLEAR_STENCIL
) {
4335 glStencilMask(This
->stateBlock
->renderState
[WINED3DRS_STENCILWRITEMASK
]);
4337 if (Flags
& WINED3DCLEAR_TARGET
) {
4338 DWORD mask
= This
->stateBlock
->renderState
[WINED3DRS_COLORWRITEENABLE
];
4339 glColorMask(mask
& WINED3DCOLORWRITEENABLE_RED
? GL_TRUE
: GL_FALSE
,
4340 mask
& WINED3DCOLORWRITEENABLE_GREEN
? GL_TRUE
: GL_FALSE
,
4341 mask
& WINED3DCOLORWRITEENABLE_BLUE
? GL_TRUE
: GL_FALSE
,
4342 mask
& WINED3DCOLORWRITEENABLE_ALPHA
? GL_TRUE
: GL_FALSE
);
4344 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4345 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4347 IWineD3DSurface_ModifyLocation((IWineD3DSurface
*)target
, SFLAG_INDRAWABLE
, TRUE
);
4349 if (Flags
& WINED3DCLEAR_ZBUFFER
) {
4350 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
4351 DWORD location
= context
->render_offscreen
? SFLAG_DS_OFFSCREEN
: SFLAG_DS_ONSCREEN
;
4352 surface_modify_ds_location(This
->stencilBufferTarget
, location
);
4357 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface
*)target
, &IID_IWineD3DSwapChain
, (void **)&swapchain
))) {
4358 if (target
== (IWineD3DSurfaceImpl
*) swapchain
->frontBuffer
) {
4361 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
4364 context_release(context
);
4369 static HRESULT WINAPI
IWineD3DDeviceImpl_Clear(IWineD3DDevice
*iface
, DWORD Count
, CONST WINED3DRECT
* pRects
,
4370 DWORD Flags
, WINED3DCOLOR Color
, float Z
, DWORD Stencil
) {
4371 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4372 IWineD3DSurfaceImpl
*target
= (IWineD3DSurfaceImpl
*)This
->render_targets
[0];
4374 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This
,
4375 Count
, pRects
, Flags
, Color
, Z
, Stencil
);
4377 if(Flags
& (WINED3DCLEAR_ZBUFFER
| WINED3DCLEAR_STENCIL
) && This
->stencilBufferTarget
== NULL
) {
4378 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4379 /* TODO: What about depth stencil buffers without stencil bits? */
4380 return WINED3DERR_INVALIDCALL
;
4383 return IWineD3DDeviceImpl_ClearSurface(This
, target
, Count
, pRects
, Flags
, Color
, Z
, Stencil
);
4390 static void WINAPI
IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice
*iface
,
4391 WINED3DPRIMITIVETYPE primitive_type
)
4393 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4395 TRACE("iface %p, primitive_type %s\n", iface
, debug_d3dprimitivetype(primitive_type
));
4397 This
->updateStateBlock
->changed
.primitive_type
= TRUE
;
4398 This
->updateStateBlock
->gl_primitive_type
= gl_primitive_type_from_d3d(primitive_type
);
4401 static void WINAPI
IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice
*iface
,
4402 WINED3DPRIMITIVETYPE
*primitive_type
)
4404 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4406 TRACE("iface %p, primitive_type %p\n", iface
, primitive_type
);
4408 *primitive_type
= d3d_primitive_type_from_gl(This
->stateBlock
->gl_primitive_type
);
4410 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type
));
4413 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice
*iface
, UINT StartVertex
, UINT vertex_count
)
4415 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4417 TRACE("(%p) : start %u, count %u\n", This
, StartVertex
, vertex_count
);
4419 if(!This
->stateBlock
->vertexDecl
) {
4420 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
4421 return WINED3DERR_INVALIDCALL
;
4424 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4425 if(This
->stateBlock
->streamIsUP
) {
4426 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
4427 This
->stateBlock
->streamIsUP
= FALSE
;
4430 if(This
->stateBlock
->loadBaseVertexIndex
!= 0) {
4431 This
->stateBlock
->loadBaseVertexIndex
= 0;
4432 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
4434 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4435 drawPrimitive(iface
, vertex_count
, StartVertex
/* start_idx */, 0 /* indxSize */, NULL
/* indxData */);
4439 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice
*iface
, UINT startIndex
, UINT index_count
)
4441 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4443 IWineD3DBuffer
*pIB
;
4446 pIB
= This
->stateBlock
->pIndexData
;
4448 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4449 * without an index buffer set. (The first time at least...)
4450 * D3D8 simply dies, but I doubt it can do much harm to return
4451 * D3DERR_INVALIDCALL there as well. */
4452 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This
);
4453 return WINED3DERR_INVALIDCALL
;
4456 if(!This
->stateBlock
->vertexDecl
) {
4457 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
4458 return WINED3DERR_INVALIDCALL
;
4461 if(This
->stateBlock
->streamIsUP
) {
4462 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
4463 This
->stateBlock
->streamIsUP
= FALSE
;
4465 vbo
= ((struct wined3d_buffer
*) pIB
)->buffer_object
;
4467 TRACE("(%p) : startIndex %u, index count %u.\n", This
, startIndex
, index_count
);
4469 if (This
->stateBlock
->IndexFmt
== WINED3DFMT_R16_UINT
) {
4475 if(This
->stateBlock
->loadBaseVertexIndex
!= This
->stateBlock
->baseVertexIndex
) {
4476 This
->stateBlock
->loadBaseVertexIndex
= This
->stateBlock
->baseVertexIndex
;
4477 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
4480 drawPrimitive(iface
, index_count
, startIndex
, idxStride
,
4481 vbo
? NULL
: ((struct wined3d_buffer
*)pIB
)->resource
.allocatedMemory
);
4486 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice
*iface
, UINT vertex_count
,
4487 const void *pVertexStreamZeroData
, UINT VertexStreamZeroStride
)
4489 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4492 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4493 This
, vertex_count
, pVertexStreamZeroData
, VertexStreamZeroStride
);
4495 if(!This
->stateBlock
->vertexDecl
) {
4496 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
4497 return WINED3DERR_INVALIDCALL
;
4500 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4501 vb
= This
->stateBlock
->streamSource
[0];
4502 This
->stateBlock
->streamSource
[0] = (IWineD3DBuffer
*)pVertexStreamZeroData
;
4503 if (vb
) IWineD3DBuffer_Release(vb
);
4504 This
->stateBlock
->streamOffset
[0] = 0;
4505 This
->stateBlock
->streamStride
[0] = VertexStreamZeroStride
;
4506 This
->stateBlock
->streamIsUP
= TRUE
;
4507 This
->stateBlock
->loadBaseVertexIndex
= 0;
4509 /* TODO: Only mark dirty if drawing from a different UP address */
4510 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
4512 drawPrimitive(iface
, vertex_count
, 0 /* start_idx */, 0 /* indxSize*/, NULL
/* indxData */);
4514 /* MSDN specifies stream zero settings must be set to NULL */
4515 This
->stateBlock
->streamStride
[0] = 0;
4516 This
->stateBlock
->streamSource
[0] = NULL
;
4518 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4519 * the new stream sources or use UP drawing again
4524 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice
*iface
,
4525 UINT index_count
, const void *pIndexData
, WINED3DFORMAT IndexDataFormat
,
4526 const void *pVertexStreamZeroData
, UINT VertexStreamZeroStride
)
4529 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4533 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4534 This
, index_count
, pIndexData
, IndexDataFormat
, pVertexStreamZeroData
, VertexStreamZeroStride
);
4536 if(!This
->stateBlock
->vertexDecl
) {
4537 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
4538 return WINED3DERR_INVALIDCALL
;
4541 if (IndexDataFormat
== WINED3DFMT_R16_UINT
) {
4547 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4548 vb
= This
->stateBlock
->streamSource
[0];
4549 This
->stateBlock
->streamSource
[0] = (IWineD3DBuffer
*)pVertexStreamZeroData
;
4550 if (vb
) IWineD3DBuffer_Release(vb
);
4551 This
->stateBlock
->streamIsUP
= TRUE
;
4552 This
->stateBlock
->streamOffset
[0] = 0;
4553 This
->stateBlock
->streamStride
[0] = VertexStreamZeroStride
;
4555 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4556 This
->stateBlock
->baseVertexIndex
= 0;
4557 This
->stateBlock
->loadBaseVertexIndex
= 0;
4558 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4559 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
4560 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
4562 drawPrimitive(iface
, index_count
, 0 /* start_idx */, idxStride
, pIndexData
);
4564 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4565 This
->stateBlock
->streamSource
[0] = NULL
;
4566 This
->stateBlock
->streamStride
[0] = 0;
4567 ib
= This
->stateBlock
->pIndexData
;
4569 IWineD3DBuffer_Release(ib
);
4570 This
->stateBlock
->pIndexData
= NULL
;
4572 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4573 * SetStreamSource to specify a vertex buffer
4579 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice
*iface
,
4580 UINT vertex_count
, const WineDirect3DVertexStridedData
*DrawPrimStrideData
)
4582 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
4584 /* Mark the state dirty until we have nicer tracking
4585 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4588 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
4589 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
4590 This
->stateBlock
->baseVertexIndex
= 0;
4591 This
->up_strided
= DrawPrimStrideData
;
4592 drawPrimitive(iface
, vertex_count
, 0, 0, NULL
);
4593 This
->up_strided
= NULL
;
4597 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice
*iface
,
4598 UINT vertex_count
, const WineDirect3DVertexStridedData
*DrawPrimStrideData
,
4599 UINT NumVertices
, const void *pIndexData
, WINED3DFORMAT IndexDataFormat
)
4601 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
4602 DWORD idxSize
= (IndexDataFormat
== WINED3DFMT_R32_UINT
? 4 : 2);
4604 /* Mark the state dirty until we have nicer tracking
4605 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4608 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
4609 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
4610 This
->stateBlock
->streamIsUP
= TRUE
;
4611 This
->stateBlock
->baseVertexIndex
= 0;
4612 This
->up_strided
= DrawPrimStrideData
;
4613 drawPrimitive(iface
, vertex_count
, 0 /* start_idx */, idxSize
, pIndexData
);
4614 This
->up_strided
= NULL
;
4618 static HRESULT
IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice
*iface
, IWineD3DVolume
*pSourceVolume
, IWineD3DVolume
*pDestinationVolume
) {
4619 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
4620 * not callable by the app directly no parameter validation checks are needed here.
4622 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
4623 WINED3DLOCKED_BOX src
;
4624 WINED3DLOCKED_BOX dst
;
4626 TRACE("(%p)->(%p, %p)\n", This
, pSourceVolume
, pDestinationVolume
);
4628 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4629 * dirtification to improve loading performance.
4631 hr
= IWineD3DVolume_LockBox(pSourceVolume
, &src
, NULL
, WINED3DLOCK_READONLY
);
4632 if(FAILED(hr
)) return hr
;
4633 hr
= IWineD3DVolume_LockBox(pDestinationVolume
, &dst
, NULL
, WINED3DLOCK_DISCARD
);
4635 IWineD3DVolume_UnlockBox(pSourceVolume
);
4639 memcpy(dst
.pBits
, src
.pBits
, ((IWineD3DVolumeImpl
*) pDestinationVolume
)->resource
.size
);
4641 hr
= IWineD3DVolume_UnlockBox(pDestinationVolume
);
4643 IWineD3DVolume_UnlockBox(pSourceVolume
);
4645 hr
= IWineD3DVolume_UnlockBox(pSourceVolume
);
4650 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice
*iface
,
4651 IWineD3DBaseTexture
*src_texture
, IWineD3DBaseTexture
*dst_texture
)
4653 unsigned int level_count
, i
;
4654 WINED3DRESOURCETYPE type
;
4657 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface
, src_texture
, dst_texture
);
4659 /* Verify that the source and destination textures are non-NULL. */
4660 if (!src_texture
|| !dst_texture
)
4662 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4663 return WINED3DERR_INVALIDCALL
;
4666 if (src_texture
== dst_texture
)
4668 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4669 return WINED3DERR_INVALIDCALL
;
4672 /* Verify that the source and destination textures are the same type. */
4673 type
= IWineD3DBaseTexture_GetType(src_texture
);
4674 if (IWineD3DBaseTexture_GetType(dst_texture
) != type
)
4676 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4677 return WINED3DERR_INVALIDCALL
;
4680 /* Check that both textures have the identical numbers of levels. */
4681 level_count
= IWineD3DBaseTexture_GetLevelCount(src_texture
);
4682 if (IWineD3DBaseTexture_GetLevelCount(dst_texture
) != level_count
)
4684 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4685 return WINED3DERR_INVALIDCALL
;
4688 /* Make sure that the destination texture is loaded. */
4689 ((IWineD3DBaseTextureImpl
*)dst_texture
)->baseTexture
.internal_preload(dst_texture
, SRGB_RGB
);
4691 /* Update every surface level of the texture. */
4694 case WINED3DRTYPE_TEXTURE
:
4696 IWineD3DSurface
*src_surface
;
4697 IWineD3DSurface
*dst_surface
;
4699 for (i
= 0; i
< level_count
; ++i
)
4701 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)src_texture
, i
, &src_surface
);
4702 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)dst_texture
, i
, &dst_surface
);
4703 hr
= IWineD3DDevice_UpdateSurface(iface
, src_surface
, NULL
, dst_surface
, NULL
);
4704 IWineD3DSurface_Release(dst_surface
);
4705 IWineD3DSurface_Release(src_surface
);
4708 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr
);
4715 case WINED3DRTYPE_CUBETEXTURE
:
4717 IWineD3DSurface
*src_surface
;
4718 IWineD3DSurface
*dst_surface
;
4719 WINED3DCUBEMAP_FACES face
;
4721 for (i
= 0; i
< level_count
; ++i
)
4723 /* Update each cube face. */
4724 for (face
= WINED3DCUBEMAP_FACE_POSITIVE_X
; face
<= WINED3DCUBEMAP_FACE_NEGATIVE_Z
; ++face
)
4726 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)src_texture
,
4727 face
, i
, &src_surface
);
4728 if (FAILED(hr
)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face
, i
, hr
);
4729 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)dst_texture
,
4730 face
, i
, &dst_surface
);
4731 if (FAILED(hr
)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face
, i
, hr
);
4732 hr
= IWineD3DDevice_UpdateSurface(iface
, src_surface
, NULL
, dst_surface
, NULL
);
4733 IWineD3DSurface_Release(dst_surface
);
4734 IWineD3DSurface_Release(src_surface
);
4737 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr
);
4745 case WINED3DRTYPE_VOLUMETEXTURE
:
4747 IWineD3DVolume
*src_volume
;
4748 IWineD3DVolume
*dst_volume
;
4750 for (i
= 0; i
< level_count
; ++i
)
4752 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture
*)src_texture
, i
, &src_volume
);
4753 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture
*)dst_texture
, i
, &dst_volume
);
4754 hr
= IWineD3DDeviceImpl_UpdateVolume(iface
, src_volume
, dst_volume
);
4755 IWineD3DVolume_Release(dst_volume
);
4756 IWineD3DVolume_Release(src_volume
);
4759 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr
);
4767 FIXME("Unsupported texture type %#x.\n", type
);
4768 return WINED3DERR_INVALIDCALL
;
4774 static HRESULT WINAPI
IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice
*iface
,UINT iSwapChain
, IWineD3DSurface
*pDestSurface
) {
4775 IWineD3DSwapChain
*swapChain
;
4777 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
4778 if(hr
== WINED3D_OK
) {
4779 hr
= IWineD3DSwapChain_GetFrontBufferData(swapChain
, pDestSurface
);
4780 IWineD3DSwapChain_Release(swapChain
);
4785 static HRESULT WINAPI
IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice
*iface
, DWORD
* pNumPasses
) {
4786 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4787 IWineD3DBaseTextureImpl
*texture
;
4790 TRACE("(%p) : %p\n", This
, pNumPasses
);
4792 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++) {
4793 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MINFILTER
] == WINED3DTEXF_NONE
) {
4794 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i
);
4795 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER
;
4797 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MAGFILTER
] == WINED3DTEXF_NONE
) {
4798 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i
);
4799 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER
;
4802 texture
= (IWineD3DBaseTextureImpl
*) This
->stateBlock
->textures
[i
];
4803 if (!texture
|| texture
->resource
.format_desc
->Flags
& WINED3DFMT_FLAG_FILTERING
) continue;
4805 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MAGFILTER
] != WINED3DTEXF_POINT
) {
4806 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i
);
4809 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MINFILTER
] != WINED3DTEXF_POINT
) {
4810 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i
);
4813 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MIPFILTER
] != WINED3DTEXF_NONE
&&
4814 This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MIPFILTER
] != WINED3DTEXF_POINT
/* sic! */) {
4815 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i
);
4820 /* return a sensible default */
4823 TRACE("returning D3D_OK\n");
4827 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl
*device
)
4831 for (i
= 0; i
< MAX_COMBINED_SAMPLERS
; ++i
)
4833 IWineD3DBaseTextureImpl
*texture
= (IWineD3DBaseTextureImpl
*)device
->stateBlock
->textures
[i
];
4834 if (texture
&& (texture
->resource
.format_desc
->format
== WINED3DFMT_P8_UINT
4835 || texture
->resource
.format_desc
->format
== WINED3DFMT_P8_UINT_A8_UNORM
))
4837 IWineD3DDeviceImpl_MarkStateDirty(device
, STATE_SAMPLER(i
));
4842 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, CONST PALETTEENTRY
* pEntries
) {
4843 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4846 PALETTEENTRY
**palettes
;
4848 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
4850 if (PaletteNumber
>= MAX_PALETTES
) {
4851 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This
, PaletteNumber
, MAX_PALETTES
);
4852 return WINED3DERR_INVALIDCALL
;
4855 if (PaletteNumber
>= This
->NumberOfPalettes
) {
4856 NewSize
= This
->NumberOfPalettes
;
4859 } while(PaletteNumber
>= NewSize
);
4860 palettes
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, This
->palettes
, sizeof(PALETTEENTRY
*) * NewSize
);
4862 ERR("Out of memory!\n");
4863 return E_OUTOFMEMORY
;
4865 This
->palettes
= palettes
;
4866 This
->NumberOfPalettes
= NewSize
;
4869 if (!This
->palettes
[PaletteNumber
]) {
4870 This
->palettes
[PaletteNumber
] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY
) * 256);
4871 if (!This
->palettes
[PaletteNumber
]) {
4872 ERR("Out of memory!\n");
4873 return E_OUTOFMEMORY
;
4877 for (j
= 0; j
< 256; ++j
) {
4878 This
->palettes
[PaletteNumber
][j
].peRed
= pEntries
[j
].peRed
;
4879 This
->palettes
[PaletteNumber
][j
].peGreen
= pEntries
[j
].peGreen
;
4880 This
->palettes
[PaletteNumber
][j
].peBlue
= pEntries
[j
].peBlue
;
4881 This
->palettes
[PaletteNumber
][j
].peFlags
= pEntries
[j
].peFlags
;
4883 if (PaletteNumber
== This
->currentPalette
) dirtify_p8_texture_samplers(This
);
4884 TRACE("(%p) : returning\n", This
);
4888 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, PALETTEENTRY
* pEntries
) {
4889 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4891 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
4892 if (PaletteNumber
>= This
->NumberOfPalettes
|| !This
->palettes
[PaletteNumber
]) {
4893 /* What happens in such situation isn't documented; Native seems to silently abort
4894 on such conditions. Return Invalid Call. */
4895 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This
, PaletteNumber
, This
->NumberOfPalettes
);
4896 return WINED3DERR_INVALIDCALL
;
4898 for (j
= 0; j
< 256; ++j
) {
4899 pEntries
[j
].peRed
= This
->palettes
[PaletteNumber
][j
].peRed
;
4900 pEntries
[j
].peGreen
= This
->palettes
[PaletteNumber
][j
].peGreen
;
4901 pEntries
[j
].peBlue
= This
->palettes
[PaletteNumber
][j
].peBlue
;
4902 pEntries
[j
].peFlags
= This
->palettes
[PaletteNumber
][j
].peFlags
;
4904 TRACE("(%p) : returning\n", This
);
4908 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT PaletteNumber
) {
4909 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4910 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
4911 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
4912 (tested with reference rasterizer). Return Invalid Call. */
4913 if (PaletteNumber
>= This
->NumberOfPalettes
|| !This
->palettes
[PaletteNumber
]) {
4914 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This
, PaletteNumber
, This
->NumberOfPalettes
);
4915 return WINED3DERR_INVALIDCALL
;
4917 /*TODO: stateblocks */
4918 if (This
->currentPalette
!= PaletteNumber
) {
4919 This
->currentPalette
= PaletteNumber
;
4920 dirtify_p8_texture_samplers(This
);
4922 TRACE("(%p) : returning\n", This
);
4926 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT
* PaletteNumber
) {
4927 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4928 if (PaletteNumber
== NULL
) {
4929 WARN("(%p) : returning Invalid Call\n", This
);
4930 return WINED3DERR_INVALIDCALL
;
4932 /*TODO: stateblocks */
4933 *PaletteNumber
= This
->currentPalette
;
4934 TRACE("(%p) : returning %u\n", This
, *PaletteNumber
);
4938 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice
*iface
, BOOL bSoftware
) {
4939 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4943 FIXME("(%p) : stub\n", This
);
4947 This
->softwareVertexProcessing
= bSoftware
;
4952 static BOOL WINAPI
IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice
*iface
) {
4953 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4957 FIXME("(%p) : stub\n", This
);
4960 return This
->softwareVertexProcessing
;
4964 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DRASTER_STATUS
* pRasterStatus
) {
4965 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4966 IWineD3DSwapChain
*swapChain
;
4969 TRACE("(%p) : SwapChain %d returning %p\n", This
, iSwapChain
, pRasterStatus
);
4971 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
4972 if(hr
== WINED3D_OK
){
4973 hr
= IWineD3DSwapChain_GetRasterStatus(swapChain
, pRasterStatus
);
4974 IWineD3DSwapChain_Release(swapChain
);
4976 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This
);
4982 static HRESULT WINAPI
IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice
*iface
, float nSegments
) {
4983 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4985 if(nSegments
!= 0.0f
) {
4988 FIXME("(%p) : stub nSegments(%f)\n", This
, nSegments
);
4995 static float WINAPI
IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice
*iface
) {
4996 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5000 FIXME("(%p) : stub returning(%f)\n", This
, 0.0f
);
5006 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice
*iface
, IWineD3DSurface
*pSourceSurface
, CONST RECT
* pSourceRect
, IWineD3DSurface
*pDestinationSurface
, CONST POINT
* pDestPoint
) {
5007 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5008 /** TODO: remove casts to IWineD3DSurfaceImpl
5009 * NOTE: move code to surface to accomplish this
5010 ****************************************/
5011 IWineD3DSurfaceImpl
*pSrcSurface
= (IWineD3DSurfaceImpl
*)pSourceSurface
;
5012 IWineD3DSurfaceImpl
*dst_impl
= (IWineD3DSurfaceImpl
*)pDestinationSurface
;
5013 int srcWidth
, srcHeight
;
5014 unsigned int srcSurfaceWidth
, srcSurfaceHeight
, destSurfaceWidth
, destSurfaceHeight
;
5015 WINED3DFORMAT destFormat
, srcFormat
;
5017 int srcLeft
, destLeft
, destTop
;
5018 WINED3DPOOL srcPool
, destPool
;
5020 int rowoffset
= 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5021 const struct GlPixelFormatDesc
*src_format_desc
, *dst_format_desc
;
5025 CONVERT_TYPES convert
= NO_CONVERSION
;
5026 struct wined3d_context
*context
;
5028 WINED3DSURFACE_DESC winedesc
;
5030 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This
, pSourceSurface
, pSourceRect
, pDestinationSurface
, pDestPoint
);
5032 IWineD3DSurface_GetDesc(pSourceSurface
, &winedesc
);
5033 srcSurfaceWidth
= winedesc
.width
;
5034 srcSurfaceHeight
= winedesc
.height
;
5035 srcPool
= winedesc
.pool
;
5036 srcFormat
= winedesc
.format
;
5038 IWineD3DSurface_GetDesc(pDestinationSurface
, &winedesc
);
5039 destSurfaceWidth
= winedesc
.width
;
5040 destSurfaceHeight
= winedesc
.height
;
5041 destPool
= winedesc
.pool
;
5042 destFormat
= winedesc
.format
;
5043 destSize
= winedesc
.size
;
5045 if(srcPool
!= WINED3DPOOL_SYSTEMMEM
|| destPool
!= WINED3DPOOL_DEFAULT
){
5046 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface
, pDestinationSurface
);
5047 return WINED3DERR_INVALIDCALL
;
5050 /* This call loads the opengl surface directly, instead of copying the surface to the
5051 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5052 * copy in sysmem and use regular surface loading.
5054 d3dfmt_get_conv(dst_impl
, FALSE
, TRUE
, &dummy
, &dummy
, &dummy
, &convert
, &bpp
, FALSE
);
5055 if(convert
!= NO_CONVERSION
) {
5056 return IWineD3DSurface_BltFast(pDestinationSurface
,
5057 pDestPoint
? pDestPoint
->x
: 0,
5058 pDestPoint
? pDestPoint
->y
: 0,
5059 pSourceSurface
, pSourceRect
, 0);
5062 if (destFormat
== WINED3DFMT_UNKNOWN
) {
5063 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This
);
5064 IWineD3DSurface_SetFormat(pDestinationSurface
, srcFormat
);
5066 /* Get the update surface description */
5067 IWineD3DSurface_GetDesc(pDestinationSurface
, &winedesc
);
5070 context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
5073 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
5074 checkGLcall("glActiveTextureARB");
5077 /* Make sure the surface is loaded and up to date */
5078 surface_internal_preload(pDestinationSurface
, SRGB_RGB
);
5079 IWineD3DSurface_BindTexture(pDestinationSurface
, FALSE
);
5081 src_format_desc
= ((IWineD3DSurfaceImpl
*)pSrcSurface
)->resource
.format_desc
;
5082 dst_format_desc
= dst_impl
->resource
.format_desc
;
5084 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5085 srcWidth
= pSourceRect
? pSourceRect
->right
- pSourceRect
->left
: srcSurfaceWidth
;
5086 srcHeight
= pSourceRect
? pSourceRect
->bottom
- pSourceRect
->top
: srcSurfaceHeight
;
5087 srcLeft
= pSourceRect
? pSourceRect
->left
: 0;
5088 destLeft
= pDestPoint
? pDestPoint
->x
: 0;
5089 destTop
= pDestPoint
? pDestPoint
->y
: 0;
5092 /* This function doesn't support compressed textures
5093 the pitch is just bytesPerPixel * width */
5094 if(srcWidth
!= srcSurfaceWidth
|| srcLeft
){
5095 rowoffset
= srcSurfaceWidth
* src_format_desc
->byte_count
;
5096 offset
+= srcLeft
* src_format_desc
->byte_count
;
5097 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5099 /* TODO DXT formats */
5101 if(pSourceRect
!= NULL
&& pSourceRect
->top
!= 0){
5102 offset
+= pSourceRect
->top
* srcSurfaceWidth
* src_format_desc
->byte_count
;
5104 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5105 This
, dst_impl
->texture_level
, destLeft
, destTop
, srcWidth
, srcHeight
, dst_format_desc
->glFormat
,
5106 dst_format_desc
->glType
, IWineD3DSurface_GetData(pSourceSurface
), offset
);
5109 if (IWineD3DSurface_GetData(pSourceSurface
) == NULL
) {
5111 /* need to lock the surface to get the data */
5112 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5117 /* TODO: Cube and volume support */
5119 /* not a whole row so we have to do it a line at a time */
5122 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5123 const unsigned char* data
=((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface
)) + offset
;
5125 for (j
= destTop
; j
< (srcHeight
+ destTop
); ++j
)
5127 glTexSubImage2D(dst_impl
->texture_target
, dst_impl
->texture_level
, destLeft
, j
,
5128 srcWidth
, 1, dst_format_desc
->glFormat
, dst_format_desc
->glType
,data
);
5132 } else { /* Full width, so just write out the whole texture */
5133 const unsigned char* data
= ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface
)) + offset
;
5135 if (dst_format_desc
->Flags
& WINED3DFMT_FLAG_COMPRESSED
)
5137 if (destSurfaceHeight
!= srcHeight
|| destSurfaceWidth
!= srcWidth
)
5139 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across. */
5140 FIXME("Updating part of a compressed texture is not supported.\n");
5142 if (destFormat
!= srcFormat
)
5144 FIXME("Updating mixed format compressed textures is not supported.\n");
5148 GL_EXTCALL(glCompressedTexImage2DARB(dst_impl
->texture_target
, dst_impl
->texture_level
,
5149 dst_format_desc
->glInternal
, srcWidth
, srcHeight
, 0, destSize
, data
));
5154 glTexSubImage2D(dst_impl
->texture_target
, dst_impl
->texture_level
, destLeft
, destTop
,
5155 srcWidth
, srcHeight
, dst_format_desc
->glFormat
, dst_format_desc
->glType
, data
);
5158 checkGLcall("glTexSubImage2D");
5161 context_release(context
);
5163 IWineD3DSurface_ModifyLocation(pDestinationSurface
, SFLAG_INTEXTURE
, TRUE
);
5164 sampler
= This
->rev_tex_unit_map
[0];
5165 if (sampler
!= WINED3D_UNMAPPED_STAGE
)
5167 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(sampler
));
5173 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice
*iface
, UINT Handle
, CONST
float* pNumSegs
, CONST WINED3DRECTPATCH_INFO
* pRectPatchInfo
) {
5174 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5175 struct WineD3DRectPatch
*patch
;
5176 GLenum old_primitive_type
;
5180 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This
, Handle
, pNumSegs
, pRectPatchInfo
);
5182 if(!(Handle
|| pRectPatchInfo
)) {
5183 /* TODO: Write a test for the return value, thus the FIXME */
5184 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5185 return WINED3DERR_INVALIDCALL
;
5189 i
= PATCHMAP_HASHFUNC(Handle
);
5191 LIST_FOR_EACH(e
, &This
->patches
[i
]) {
5192 patch
= LIST_ENTRY(e
, struct WineD3DRectPatch
, entry
);
5193 if(patch
->Handle
== Handle
) {
5200 TRACE("Patch does not exist. Creating a new one\n");
5201 patch
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*patch
));
5202 patch
->Handle
= Handle
;
5203 list_add_head(&This
->patches
[i
], &patch
->entry
);
5205 TRACE("Found existing patch %p\n", patch
);
5208 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5209 * attributes we have to tesselate, read back, and draw. This needs a patch
5210 * management structure instance. Create one.
5212 * A possible improvement is to check if a vertex shader is used, and if not directly
5215 FIXME("Drawing an uncached patch. This is slow\n");
5216 patch
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*patch
));
5219 if(pNumSegs
[0] != patch
->numSegs
[0] || pNumSegs
[1] != patch
->numSegs
[1] ||
5220 pNumSegs
[2] != patch
->numSegs
[2] || pNumSegs
[3] != patch
->numSegs
[3] ||
5221 (pRectPatchInfo
&& memcmp(pRectPatchInfo
, &patch
->RectPatchInfo
, sizeof(*pRectPatchInfo
)) != 0) ) {
5223 TRACE("Tesselation density or patch info changed, retesselating\n");
5225 if(pRectPatchInfo
) {
5226 patch
->RectPatchInfo
= *pRectPatchInfo
;
5228 patch
->numSegs
[0] = pNumSegs
[0];
5229 patch
->numSegs
[1] = pNumSegs
[1];
5230 patch
->numSegs
[2] = pNumSegs
[2];
5231 patch
->numSegs
[3] = pNumSegs
[3];
5233 hr
= tesselate_rectpatch(This
, patch
);
5235 WARN("Patch tesselation failed\n");
5237 /* Do not release the handle to store the params of the patch */
5239 HeapFree(GetProcessHeap(), 0, patch
);
5245 This
->currentPatch
= patch
;
5246 old_primitive_type
= This
->stateBlock
->gl_primitive_type
;
5247 This
->stateBlock
->gl_primitive_type
= GL_TRIANGLES
;
5248 IWineD3DDevice_DrawPrimitiveStrided(iface
, patch
->numSegs
[0] * patch
->numSegs
[1] * 2 * 3, &patch
->strided
);
5249 This
->stateBlock
->gl_primitive_type
= old_primitive_type
;
5250 This
->currentPatch
= NULL
;
5252 /* Destroy uncached patches */
5254 HeapFree(GetProcessHeap(), 0, patch
->mem
);
5255 HeapFree(GetProcessHeap(), 0, patch
);
5260 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice
*iface
, UINT Handle
, CONST
float* pNumSegs
, CONST WINED3DTRIPATCH_INFO
* pTriPatchInfo
) {
5261 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5262 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This
, Handle
, pNumSegs
, pTriPatchInfo
);
5263 FIXME("(%p) : Stub\n", This
);
5267 static HRESULT WINAPI
IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice
*iface
, UINT Handle
) {
5268 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5270 struct WineD3DRectPatch
*patch
;
5272 TRACE("(%p) Handle(%d)\n", This
, Handle
);
5274 i
= PATCHMAP_HASHFUNC(Handle
);
5275 LIST_FOR_EACH(e
, &This
->patches
[i
]) {
5276 patch
= LIST_ENTRY(e
, struct WineD3DRectPatch
, entry
);
5277 if(patch
->Handle
== Handle
) {
5278 TRACE("Deleting patch %p\n", patch
);
5279 list_remove(&patch
->entry
);
5280 HeapFree(GetProcessHeap(), 0, patch
->mem
);
5281 HeapFree(GetProcessHeap(), 0, patch
);
5286 /* TODO: Write a test for the return value */
5287 FIXME("Attempt to destroy nonexistent patch\n");
5288 return WINED3DERR_INVALIDCALL
;
5291 static IWineD3DSwapChain
*get_swapchain(IWineD3DSurface
*target
) {
5293 IWineD3DSwapChain
*swapchain
;
5295 hr
= IWineD3DSurface_GetContainer(target
, &IID_IWineD3DSwapChain
, (void **)&swapchain
);
5296 if (SUCCEEDED(hr
)) {
5297 IWineD3DSwapChain_Release((IUnknown
*)swapchain
);
5304 static void color_fill_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*surface
,
5305 const WINED3DRECT
*rect
, const float color
[4])
5307 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5308 struct wined3d_context
*context
;
5309 IWineD3DSwapChain
*swapchain
;
5311 swapchain
= get_swapchain(surface
);
5312 if (!surface_is_offscreen(surface
))
5314 TRACE("Surface %p is onscreen\n", surface
);
5316 context
= context_acquire(This
, surface
, CTXUSAGE_RESOURCELOAD
);
5318 context_bind_fbo(context
, GL_FRAMEBUFFER
, NULL
);
5319 context_set_draw_buffer(context
, surface_get_gl_buffer(surface
, swapchain
));
5323 TRACE("Surface %p is offscreen\n", surface
);
5325 context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
5327 context_bind_fbo(context
, GL_FRAMEBUFFER
, &context
->dst_fbo
);
5328 context_attach_surface_fbo(context
, GL_FRAMEBUFFER
, 0, surface
);
5329 context_attach_depth_stencil_fbo(context
, GL_FRAMEBUFFER
, NULL
, FALSE
);
5333 glEnable(GL_SCISSOR_TEST
);
5334 if(surface_is_offscreen(surface
)) {
5335 glScissor(rect
->x1
, rect
->y1
, rect
->x2
- rect
->x1
, rect
->y2
- rect
->y1
);
5337 glScissor(rect
->x1
, ((IWineD3DSurfaceImpl
*)surface
)->currentDesc
.Height
- rect
->y2
,
5338 rect
->x2
- rect
->x1
, rect
->y2
- rect
->y1
);
5340 checkGLcall("glScissor");
5341 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SCISSORRECT
);
5343 glDisable(GL_SCISSOR_TEST
);
5345 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE
));
5347 glDisable(GL_BLEND
);
5348 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE
));
5350 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
5351 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE
));
5353 glClearColor(color
[0], color
[1], color
[2], color
[3]);
5354 glClear(GL_COLOR_BUFFER_BIT
);
5355 checkGLcall("glClear");
5358 context_release(context
);
5361 static inline DWORD
argb_to_fmt(DWORD color
, WINED3DFORMAT destfmt
) {
5362 unsigned int r
, g
, b
, a
;
5365 if (destfmt
== WINED3DFMT_B8G8R8A8_UNORM
5366 || destfmt
== WINED3DFMT_B8G8R8X8_UNORM
5367 || destfmt
== WINED3DFMT_B8G8R8_UNORM
)
5370 TRACE("Converting color %08x to format %s\n", color
, debug_d3dformat(destfmt
));
5372 a
= (color
& 0xff000000) >> 24;
5373 r
= (color
& 0x00ff0000) >> 16;
5374 g
= (color
& 0x0000ff00) >> 8;
5375 b
= (color
& 0x000000ff) >> 0;
5379 case WINED3DFMT_B5G6R5_UNORM
:
5380 if(r
== 0xff && g
== 0xff && b
== 0xff) return 0xffff;
5387 TRACE("Returning %08x\n", ret
);
5390 case WINED3DFMT_B5G5R5X1_UNORM
:
5391 case WINED3DFMT_B5G5R5A1_UNORM
:
5400 TRACE("Returning %08x\n", ret
);
5403 case WINED3DFMT_A8_UNORM
:
5404 TRACE("Returning %08x\n", a
);
5407 case WINED3DFMT_B4G4R4X4_UNORM
:
5408 case WINED3DFMT_B4G4R4A4_UNORM
:
5417 TRACE("Returning %08x\n", ret
);
5420 case WINED3DFMT_B2G3R3_UNORM
:
5427 TRACE("Returning %08x\n", ret
);
5430 case WINED3DFMT_R8G8B8X8_UNORM
:
5431 case WINED3DFMT_R8G8B8A8_UNORM
:
5436 TRACE("Returning %08x\n", ret
);
5439 case WINED3DFMT_B10G10R10A2_UNORM
:
5441 r
= (r
* 1024) / 256;
5442 g
= (g
* 1024) / 256;
5443 b
= (b
* 1024) / 256;
5448 TRACE("Returning %08x\n", ret
);
5451 case WINED3DFMT_R10G10B10A2_UNORM
:
5453 r
= (r
* 1024) / 256;
5454 g
= (g
* 1024) / 256;
5455 b
= (b
* 1024) / 256;
5460 TRACE("Returning %08x\n", ret
);
5464 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt
));
5469 static HRESULT WINAPI
IWineD3DDeviceImpl_ColorFill(IWineD3DDevice
*iface
, IWineD3DSurface
*pSurface
, CONST WINED3DRECT
* pRect
, WINED3DCOLOR color
) {
5470 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5471 IWineD3DSurfaceImpl
*surface
= (IWineD3DSurfaceImpl
*) pSurface
;
5473 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This
, pSurface
, pRect
, color
);
5475 if (surface
->resource
.pool
!= WINED3DPOOL_DEFAULT
&& surface
->resource
.pool
!= WINED3DPOOL_SYSTEMMEM
) {
5476 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5477 return WINED3DERR_INVALIDCALL
;
5480 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
5481 const float c
[4] = {D3DCOLOR_R(color
), D3DCOLOR_G(color
), D3DCOLOR_B(color
), D3DCOLOR_A(color
)};
5482 color_fill_fbo(iface
, pSurface
, pRect
, c
);
5485 /* Just forward this to the DirectDraw blitting engine */
5486 memset(&BltFx
, 0, sizeof(BltFx
));
5487 BltFx
.dwSize
= sizeof(BltFx
);
5488 BltFx
.u5
.dwFillColor
= argb_to_fmt(color
, surface
->resource
.format_desc
->format
);
5489 return IWineD3DSurface_Blt(pSurface
, (const RECT
*)pRect
, NULL
, NULL
,
5490 WINEDDBLT_COLORFILL
, &BltFx
, WINED3DTEXF_POINT
);
5494 static void WINAPI
IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice
*iface
,
5495 IWineD3DRendertargetView
*rendertarget_view
, const float color
[4])
5497 IWineD3DResource
*resource
;
5498 IWineD3DSurface
*surface
;
5501 hr
= IWineD3DRendertargetView_GetResource(rendertarget_view
, &resource
);
5504 ERR("Failed to get resource, hr %#x\n", hr
);
5508 if (IWineD3DResource_GetType(resource
) != WINED3DRTYPE_SURFACE
)
5510 FIXME("Only supported on surface resources\n");
5511 IWineD3DResource_Release(resource
);
5515 surface
= (IWineD3DSurface
*)resource
;
5517 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
)
5519 color_fill_fbo(iface
, surface
, NULL
, color
);
5526 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5528 c
= ((DWORD
)(color
[2] * 255.0f
));
5529 c
|= ((DWORD
)(color
[1] * 255.0f
)) << 8;
5530 c
|= ((DWORD
)(color
[0] * 255.0f
)) << 16;
5531 c
|= ((DWORD
)(color
[3] * 255.0f
)) << 24;
5533 /* Just forward this to the DirectDraw blitting engine */
5534 memset(&BltFx
, 0, sizeof(BltFx
));
5535 BltFx
.dwSize
= sizeof(BltFx
);
5536 BltFx
.u5
.dwFillColor
= argb_to_fmt(c
, ((IWineD3DSurfaceImpl
*)surface
)->resource
.format_desc
->format
);
5537 hr
= IWineD3DSurface_Blt(surface
, NULL
, NULL
, NULL
, WINEDDBLT_COLORFILL
, &BltFx
, WINED3DTEXF_POINT
);
5540 ERR("Blt failed, hr %#x\n", hr
);
5544 IWineD3DResource_Release(resource
);
5547 /* rendertarget and depth stencil functions */
5548 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice
* iface
,DWORD RenderTargetIndex
, IWineD3DSurface
**ppRenderTarget
) {
5549 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5551 if (RenderTargetIndex
>= This
->adapter
->gl_info
.limits
.buffers
)
5553 ERR("(%p) : Only %d render targets are supported.\n",
5554 This
, This
->adapter
->gl_info
.limits
.buffers
);
5555 return WINED3DERR_INVALIDCALL
;
5558 *ppRenderTarget
= This
->render_targets
[RenderTargetIndex
];
5559 TRACE("(%p) : RenderTarget %d Index returning %p\n", This
, RenderTargetIndex
, *ppRenderTarget
);
5560 /* Note inc ref on returned surface */
5561 if(*ppRenderTarget
!= NULL
)
5562 IWineD3DSurface_AddRef(*ppRenderTarget
);
5566 static HRESULT WINAPI
IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice
*iface
, IWineD3DSurface
*Front
, IWineD3DSurface
*Back
) {
5567 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5568 IWineD3DSurfaceImpl
*FrontImpl
= (IWineD3DSurfaceImpl
*) Front
;
5569 IWineD3DSurfaceImpl
*BackImpl
= (IWineD3DSurfaceImpl
*) Back
;
5570 IWineD3DSwapChainImpl
*Swapchain
;
5573 TRACE("(%p)->(%p,%p)\n", This
, FrontImpl
, BackImpl
);
5575 hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**) &Swapchain
);
5576 if(hr
!= WINED3D_OK
) {
5577 ERR("Can't get the swapchain\n");
5581 /* Make sure to release the swapchain */
5582 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) Swapchain
);
5584 if(FrontImpl
&& !(FrontImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) ) {
5585 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5586 return WINED3DERR_INVALIDCALL
;
5588 else if(BackImpl
&& !(BackImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)) {
5589 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5590 return WINED3DERR_INVALIDCALL
;
5593 if(Swapchain
->frontBuffer
!= Front
) {
5594 TRACE("Changing the front buffer from %p to %p\n", Swapchain
->frontBuffer
, Front
);
5596 if(Swapchain
->frontBuffer
)
5598 IWineD3DSurface_SetContainer(Swapchain
->frontBuffer
, NULL
);
5599 ((IWineD3DSurfaceImpl
*)Swapchain
->frontBuffer
)->Flags
&= ~SFLAG_SWAPCHAIN
;
5601 Swapchain
->frontBuffer
= Front
;
5603 if(Swapchain
->frontBuffer
) {
5604 IWineD3DSurface_SetContainer(Swapchain
->frontBuffer
, (IWineD3DBase
*) Swapchain
);
5605 ((IWineD3DSurfaceImpl
*)Swapchain
->frontBuffer
)->Flags
|= SFLAG_SWAPCHAIN
;
5609 if(Back
&& !Swapchain
->backBuffer
) {
5610 /* We need memory for the back buffer array - only one back buffer this way */
5611 Swapchain
->backBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DSurface
*));
5612 if(!Swapchain
->backBuffer
) {
5613 ERR("Out of memory\n");
5614 return E_OUTOFMEMORY
;
5618 if(Swapchain
->backBuffer
[0] != Back
) {
5619 TRACE("Changing the back buffer from %p to %p\n", Swapchain
->backBuffer
, Back
);
5621 /* What to do about the context here in the case of multithreading? Not sure.
5622 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5624 WARN("No active context?\n");
5627 if(!Swapchain
->backBuffer
[0]) {
5628 /* GL was told to draw to the front buffer at creation,
5631 glDrawBuffer(GL_BACK
);
5632 checkGLcall("glDrawBuffer(GL_BACK)");
5633 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5634 Swapchain
->presentParms
.BackBufferCount
= 1;
5636 /* That makes problems - disable for now */
5637 /* glDrawBuffer(GL_FRONT); */
5638 checkGLcall("glDrawBuffer(GL_FRONT)");
5639 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5640 Swapchain
->presentParms
.BackBufferCount
= 0;
5644 if(Swapchain
->backBuffer
[0])
5646 IWineD3DSurface_SetContainer(Swapchain
->backBuffer
[0], NULL
);
5647 ((IWineD3DSurfaceImpl
*)Swapchain
->backBuffer
[0])->Flags
&= ~SFLAG_SWAPCHAIN
;
5649 Swapchain
->backBuffer
[0] = Back
;
5651 if(Swapchain
->backBuffer
[0]) {
5652 IWineD3DSurface_SetContainer(Swapchain
->backBuffer
[0], (IWineD3DBase
*) Swapchain
);
5653 ((IWineD3DSurfaceImpl
*)Swapchain
->backBuffer
[0])->Flags
|= SFLAG_SWAPCHAIN
;
5655 HeapFree(GetProcessHeap(), 0, Swapchain
->backBuffer
);
5656 Swapchain
->backBuffer
= NULL
;
5664 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice
* iface
, IWineD3DSurface
**ppZStencilSurface
) {
5665 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5667 DWORD size
= sizeof(buffer
);
5669 *ppZStencilSurface
= This
->stencilBufferTarget
;
5670 /* @@ Wine registry key: HKCU\Software\Wine\Direct3D\MystIVStartupHack */
5671 if (!RegOpenKeyA( HKEY_CURRENT_USER
, "Software\\Wine\\Direct3D", &hkey
)) {
5672 if (!RegQueryValueExA( hkey
, "MystIVStartupHack", 0, NULL
, buffer
, &size
)) {
5673 if ( IS_OPTION_TRUE( buffer
[0] ) ) {
5674 TRACE("Enabling MystIVStartupHack hack\n");
5675 *ppZStencilSurface
= This
->auto_depth_stencil_buffer
;
5679 TRACE("(%p) : zStencilSurface returning %p\n", This
, *ppZStencilSurface
);
5681 if(*ppZStencilSurface
!= NULL
) {
5682 /* Note inc ref on returned surface */
5683 IWineD3DSurface_AddRef(*ppZStencilSurface
);
5686 return WINED3DERR_NOTFOUND
;
5690 void stretch_rect_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*src_surface
, WINED3DRECT
*src_rect
,
5691 IWineD3DSurface
*dst_surface
, WINED3DRECT
*dst_rect
, const WINED3DTEXTUREFILTERTYPE filter
, BOOL flip
)
5693 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5694 GLbitfield mask
= GL_COLOR_BUFFER_BIT
; /* TODO: Support blitting depth/stencil surfaces */
5695 IWineD3DSwapChain
*src_swapchain
, *dst_swapchain
;
5696 const struct wined3d_gl_info
*gl_info
;
5697 struct wined3d_context
*context
;
5699 POINT offset
= {0, 0};
5701 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5702 This
, src_surface
, src_rect
, dst_surface
, dst_rect
, debug_d3dtexturefiltertype(filter
), filter
, flip
);
5703 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
);
5704 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect
->x1
, dst_rect
->y1
, dst_rect
->x2
, dst_rect
->y2
);
5707 case WINED3DTEXF_LINEAR
:
5708 gl_filter
= GL_LINEAR
;
5712 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter
), filter
);
5713 case WINED3DTEXF_NONE
:
5714 case WINED3DTEXF_POINT
:
5715 gl_filter
= GL_NEAREST
;
5719 /* Attach src surface to src fbo */
5720 src_swapchain
= get_swapchain(src_surface
);
5721 dst_swapchain
= get_swapchain(dst_surface
);
5723 if (src_swapchain
) context
= context_acquire(This
, src_surface
, CTXUSAGE_RESOURCELOAD
);
5724 else if (dst_swapchain
) context
= context_acquire(This
, dst_surface
, CTXUSAGE_RESOURCELOAD
);
5725 else context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
5727 gl_info
= context
->gl_info
;
5729 if (!surface_is_offscreen(src_surface
)) {
5730 GLenum buffer
= surface_get_gl_buffer(src_surface
, src_swapchain
);
5732 TRACE("Source surface %p is onscreen\n", src_surface
);
5733 /* Make sure the drawable is up to date. In the offscreen case
5734 * attach_surface_fbo() implicitly takes care of this. */
5735 IWineD3DSurface_LoadLocation(src_surface
, SFLAG_INDRAWABLE
, NULL
);
5737 if(buffer
== GL_FRONT
) {
5740 ClientToScreen(((IWineD3DSwapChainImpl
*)src_swapchain
)->win_handle
, &offset
);
5741 GetClientRect(((IWineD3DSwapChainImpl
*)src_swapchain
)->win_handle
, &windowsize
);
5742 h
= windowsize
.bottom
- windowsize
.top
;
5743 src_rect
->x1
-= offset
.x
; src_rect
->x2
-=offset
.x
;
5744 src_rect
->y1
= offset
.y
+ h
- src_rect
->y1
;
5745 src_rect
->y2
= offset
.y
+ h
- src_rect
->y2
;
5747 src_rect
->y1
= ((IWineD3DSurfaceImpl
*)src_surface
)->currentDesc
.Height
- src_rect
->y1
;
5748 src_rect
->y2
= ((IWineD3DSurfaceImpl
*)src_surface
)->currentDesc
.Height
- src_rect
->y2
;
5752 context_bind_fbo(context
, GL_READ_FRAMEBUFFER
, NULL
);
5753 glReadBuffer(buffer
);
5754 checkGLcall("glReadBuffer()");
5756 TRACE("Source surface %p is offscreen\n", src_surface
);
5758 context_bind_fbo(context
, GL_READ_FRAMEBUFFER
, &context
->src_fbo
);
5759 context_attach_surface_fbo(context
, GL_READ_FRAMEBUFFER
, 0, src_surface
);
5760 glReadBuffer(GL_COLOR_ATTACHMENT0
);
5761 checkGLcall("glReadBuffer()");
5762 context_attach_depth_stencil_fbo(context
, GL_READ_FRAMEBUFFER
, NULL
, FALSE
);
5766 /* Attach dst surface to dst fbo */
5767 if (!surface_is_offscreen(dst_surface
)) {
5768 GLenum buffer
= surface_get_gl_buffer(dst_surface
, dst_swapchain
);
5770 TRACE("Destination surface %p is onscreen\n", dst_surface
);
5771 /* Make sure the drawable is up to date. In the offscreen case
5772 * attach_surface_fbo() implicitly takes care of this. */
5773 IWineD3DSurface_LoadLocation(dst_surface
, SFLAG_INDRAWABLE
, NULL
);
5775 if(buffer
== GL_FRONT
) {
5778 ClientToScreen(((IWineD3DSwapChainImpl
*)dst_swapchain
)->win_handle
, &offset
);
5779 GetClientRect(((IWineD3DSwapChainImpl
*)dst_swapchain
)->win_handle
, &windowsize
);
5780 h
= windowsize
.bottom
- windowsize
.top
;
5781 dst_rect
->x1
-= offset
.x
; dst_rect
->x2
-=offset
.x
;
5782 dst_rect
->y1
= offset
.y
+ h
- dst_rect
->y1
;
5783 dst_rect
->y2
= offset
.y
+ h
- dst_rect
->y2
;
5785 /* Screen coords = window coords, surface height = window height */
5786 dst_rect
->y1
= ((IWineD3DSurfaceImpl
*)dst_surface
)->currentDesc
.Height
- dst_rect
->y1
;
5787 dst_rect
->y2
= ((IWineD3DSurfaceImpl
*)dst_surface
)->currentDesc
.Height
- dst_rect
->y2
;
5791 context_bind_fbo(context
, GL_DRAW_FRAMEBUFFER
, NULL
);
5792 glDrawBuffer(buffer
);
5793 checkGLcall("glDrawBuffer()");
5795 TRACE("Destination surface %p is offscreen\n", dst_surface
);
5798 context_bind_fbo(context
, GL_DRAW_FRAMEBUFFER
, &context
->dst_fbo
);
5799 context_attach_surface_fbo(context
, GL_DRAW_FRAMEBUFFER
, 0, dst_surface
);
5800 glDrawBuffer(GL_COLOR_ATTACHMENT0
);
5801 checkGLcall("glDrawBuffer()");
5802 context_attach_depth_stencil_fbo(context
, GL_DRAW_FRAMEBUFFER
, NULL
, FALSE
);
5804 glDisable(GL_SCISSOR_TEST
);
5805 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE
));
5808 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
,
5809 dst_rect
->x1
, dst_rect
->y2
, dst_rect
->x2
, dst_rect
->y1
, mask
, gl_filter
);
5810 checkGLcall("glBlitFramebuffer()");
5812 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
,
5813 dst_rect
->x1
, dst_rect
->y1
, dst_rect
->x2
, dst_rect
->y2
, mask
, gl_filter
);
5814 checkGLcall("glBlitFramebuffer()");
5817 IWineD3DSurface_ModifyLocation(dst_surface
, SFLAG_INDRAWABLE
, TRUE
);
5819 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
5820 if (dst_swapchain
&& dst_surface
== ((IWineD3DSwapChainImpl
*)dst_swapchain
)->frontBuffer
5821 && ((IWineD3DSwapChainImpl
*)dst_swapchain
)->backBuffer
) {
5822 glDrawBuffer(GL_BACK
);
5823 checkGLcall("glDrawBuffer()");
5827 context_release(context
);
5830 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice
*iface
, DWORD RenderTargetIndex
, IWineD3DSurface
*pRenderTarget
,
5831 BOOL set_viewport
) {
5832 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5834 TRACE("(%p) : Setting rendertarget %d to %p\n", This
, RenderTargetIndex
, pRenderTarget
);
5836 if (RenderTargetIndex
>= This
->adapter
->gl_info
.limits
.buffers
)
5838 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
5839 This
, RenderTargetIndex
, This
->adapter
->gl_info
.limits
.buffers
);
5840 return WINED3DERR_INVALIDCALL
;
5843 /* MSDN says that null disables the render target
5844 but a device must always be associated with a render target
5845 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5847 if (RenderTargetIndex
== 0 && pRenderTarget
== NULL
) {
5848 FIXME("Trying to set render target 0 to NULL\n");
5849 return WINED3DERR_INVALIDCALL
;
5851 if (pRenderTarget
&& !(((IWineD3DSurfaceImpl
*)pRenderTarget
)->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)) {
5852 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
);
5853 return WINED3DERR_INVALIDCALL
;
5856 /* If we are trying to set what we already have, don't bother */
5857 if (pRenderTarget
== This
->render_targets
[RenderTargetIndex
]) {
5858 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5861 if(pRenderTarget
) IWineD3DSurface_AddRef(pRenderTarget
);
5862 if(This
->render_targets
[RenderTargetIndex
]) IWineD3DSurface_Release(This
->render_targets
[RenderTargetIndex
]);
5863 This
->render_targets
[RenderTargetIndex
] = pRenderTarget
;
5865 /* Render target 0 is special */
5866 if(RenderTargetIndex
== 0 && set_viewport
) {
5867 /* Finally, reset the viewport and scissor rect as the MSDN states.
5868 * Tests show that stateblock recording is ignored, the change goes
5869 * directly into the primary stateblock.
5871 This
->stateBlock
->viewport
.Height
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Height
;
5872 This
->stateBlock
->viewport
.Width
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Width
;
5873 This
->stateBlock
->viewport
.X
= 0;
5874 This
->stateBlock
->viewport
.Y
= 0;
5875 This
->stateBlock
->viewport
.MaxZ
= 1.0f
;
5876 This
->stateBlock
->viewport
.MinZ
= 0.0f
;
5877 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VIEWPORT
);
5879 This
->stateBlock
->scissorRect
.top
= 0;
5880 This
->stateBlock
->scissorRect
.left
= 0;
5881 This
->stateBlock
->scissorRect
.right
= This
->stateBlock
->viewport
.Width
;
5882 This
->stateBlock
->scissorRect
.bottom
= This
->stateBlock
->viewport
.Height
;
5883 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SCISSORRECT
);
5888 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice
*iface
, IWineD3DSurface
*pNewZStencil
) {
5889 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5890 HRESULT hr
= WINED3D_OK
;
5891 IWineD3DSurface
*tmp
;
5893 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This
, This
->stencilBufferTarget
, pNewZStencil
);
5895 if (pNewZStencil
== This
->stencilBufferTarget
) {
5896 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5898 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
5899 * depending on the renter target implementation being used.
5900 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5901 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5902 * stencil buffer and incur an extra memory overhead
5903 ******************************************************/
5905 if (This
->stencilBufferTarget
) {
5906 if (((IWineD3DSwapChainImpl
*)This
->swapchains
[0])->presentParms
.Flags
& WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5907 || ((IWineD3DSurfaceImpl
*)This
->stencilBufferTarget
)->Flags
& SFLAG_DISCARD
) {
5908 surface_modify_ds_location(This
->stencilBufferTarget
, SFLAG_DS_DISCARDED
);
5910 struct wined3d_context
*context
= context_acquire(This
, This
->render_targets
[0], CTXUSAGE_RESOURCELOAD
);
5911 surface_load_ds_location(This
->stencilBufferTarget
, context
, SFLAG_DS_OFFSCREEN
);
5912 surface_modify_ds_location(This
->stencilBufferTarget
, SFLAG_DS_OFFSCREEN
);
5913 context_release(context
);
5917 tmp
= This
->stencilBufferTarget
;
5918 This
->stencilBufferTarget
= pNewZStencil
;
5919 /* should we be calling the parent or the wined3d surface? */
5920 if (NULL
!= This
->stencilBufferTarget
) IWineD3DSurface_AddRef(This
->stencilBufferTarget
);
5921 if (NULL
!= tmp
) IWineD3DSurface_Release(tmp
);
5924 if((!tmp
&& pNewZStencil
) || (!pNewZStencil
&& tmp
)) {
5925 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5926 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ZENABLE
));
5927 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_STENCILENABLE
));
5928 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_STENCILWRITEMASK
));
5935 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice
* iface
, UINT XHotSpot
,
5936 UINT YHotSpot
, IWineD3DSurface
*pCursorBitmap
) {
5937 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5938 /* TODO: the use of Impl is deprecated. */
5939 IWineD3DSurfaceImpl
* pSur
= (IWineD3DSurfaceImpl
*) pCursorBitmap
;
5940 WINED3DLOCKED_RECT lockedRect
;
5942 TRACE("(%p) : Spot Pos(%u,%u)\n", This
, XHotSpot
, YHotSpot
);
5944 /* some basic validation checks */
5945 if(This
->cursorTexture
) {
5946 struct wined3d_context
*context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
5948 glDeleteTextures(1, &This
->cursorTexture
);
5950 context_release(context
);
5951 This
->cursorTexture
= 0;
5954 if ( (pSur
->currentDesc
.Width
== 32) && (pSur
->currentDesc
.Height
== 32) )
5955 This
->haveHardwareCursor
= TRUE
;
5957 This
->haveHardwareCursor
= FALSE
;
5960 WINED3DLOCKED_RECT rect
;
5962 /* MSDN: Cursor must be A8R8G8B8 */
5963 if (pSur
->resource
.format_desc
->format
!= WINED3DFMT_B8G8R8A8_UNORM
)
5965 ERR("(%p) : surface(%p) has an invalid format\n", This
, pCursorBitmap
);
5966 return WINED3DERR_INVALIDCALL
;
5969 /* MSDN: Cursor must be smaller than the display mode */
5970 if(pSur
->currentDesc
.Width
> This
->ddraw_width
||
5971 pSur
->currentDesc
.Height
> This
->ddraw_height
) {
5972 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
);
5973 return WINED3DERR_INVALIDCALL
;
5976 if (!This
->haveHardwareCursor
) {
5977 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5979 /* Do not store the surface's pointer because the application may
5980 * release it after setting the cursor image. Windows doesn't
5981 * addref the set surface, so we can't do this either without
5982 * creating circular refcount dependencies. Copy out the gl texture
5985 This
->cursorWidth
= pSur
->currentDesc
.Width
;
5986 This
->cursorHeight
= pSur
->currentDesc
.Height
;
5987 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap
, &rect
, NULL
, WINED3DLOCK_READONLY
)))
5989 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
5990 const struct GlPixelFormatDesc
*glDesc
= getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM
, gl_info
);
5991 struct wined3d_context
*context
;
5992 char *mem
, *bits
= rect
.pBits
;
5993 GLint intfmt
= glDesc
->glInternal
;
5994 GLint format
= glDesc
->glFormat
;
5995 GLint type
= glDesc
->glType
;
5996 INT height
= This
->cursorHeight
;
5997 INT width
= This
->cursorWidth
;
5998 INT bpp
= glDesc
->byte_count
;
6002 /* Reformat the texture memory (pitch and width can be
6004 mem
= HeapAlloc(GetProcessHeap(), 0, width
* height
* bpp
);
6005 for(i
= 0; i
< height
; i
++)
6006 memcpy(&mem
[width
* bpp
* i
], &bits
[rect
.Pitch
* i
], width
* bpp
);
6007 IWineD3DSurface_UnlockRect(pCursorBitmap
);
6009 context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
6013 if (gl_info
->supported
[APPLE_CLIENT_STORAGE
])
6015 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
6016 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6019 /* Make sure that a proper texture unit is selected */
6020 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
6021 checkGLcall("glActiveTextureARB");
6022 sampler
= This
->rev_tex_unit_map
[0];
6023 if (sampler
!= WINED3D_UNMAPPED_STAGE
)
6025 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(sampler
));
6027 /* Create a new cursor texture */
6028 glGenTextures(1, &This
->cursorTexture
);
6029 checkGLcall("glGenTextures");
6030 glBindTexture(GL_TEXTURE_2D
, This
->cursorTexture
);
6031 checkGLcall("glBindTexture");
6032 /* Copy the bitmap memory into the cursor texture */
6033 glTexImage2D(GL_TEXTURE_2D
, 0, intfmt
, width
, height
, 0, format
, type
, mem
);
6034 HeapFree(GetProcessHeap(), 0, mem
);
6035 checkGLcall("glTexImage2D");
6037 if (gl_info
->supported
[APPLE_CLIENT_STORAGE
])
6039 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
6040 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6045 context_release(context
);
6049 FIXME("A cursor texture was not returned.\n");
6050 This
->cursorTexture
= 0;
6055 /* Draw a hardware cursor */
6056 ICONINFO cursorInfo
;
6058 /* Create and clear maskBits because it is not needed for
6059 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6061 DWORD
*maskBits
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
6062 (pSur
->currentDesc
.Width
* pSur
->currentDesc
.Height
/ 8));
6063 IWineD3DSurface_LockRect(pCursorBitmap
, &lockedRect
, NULL
,
6064 WINED3DLOCK_NO_DIRTY_UPDATE
|
6065 WINED3DLOCK_READONLY
6067 TRACE("width: %i height: %i\n", pSur
->currentDesc
.Width
,
6068 pSur
->currentDesc
.Height
);
6070 cursorInfo
.fIcon
= FALSE
;
6071 cursorInfo
.xHotspot
= XHotSpot
;
6072 cursorInfo
.yHotspot
= YHotSpot
;
6073 cursorInfo
.hbmMask
= CreateBitmap(pSur
->currentDesc
.Width
, pSur
->currentDesc
.Height
,
6075 cursorInfo
.hbmColor
= CreateBitmap(pSur
->currentDesc
.Width
, pSur
->currentDesc
.Height
,
6076 1, 32, lockedRect
.pBits
);
6077 IWineD3DSurface_UnlockRect(pCursorBitmap
);
6078 /* Create our cursor and clean up. */
6079 cursor
= CreateIconIndirect(&cursorInfo
);
6081 if (cursorInfo
.hbmMask
) DeleteObject(cursorInfo
.hbmMask
);
6082 if (cursorInfo
.hbmColor
) DeleteObject(cursorInfo
.hbmColor
);
6083 if (This
->hardwareCursor
) DestroyCursor(This
->hardwareCursor
);
6084 This
->hardwareCursor
= cursor
;
6085 HeapFree(GetProcessHeap(), 0, maskBits
);
6089 This
->xHotSpot
= XHotSpot
;
6090 This
->yHotSpot
= YHotSpot
;
6094 static void WINAPI
IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice
* iface
, int XScreenSpace
, int YScreenSpace
, DWORD Flags
) {
6095 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6096 TRACE("(%p) : SetPos to (%u,%u)\n", This
, XScreenSpace
, YScreenSpace
);
6098 This
->xScreenSpace
= XScreenSpace
;
6099 This
->yScreenSpace
= YScreenSpace
;
6105 static BOOL WINAPI
IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice
* iface
, BOOL bShow
) {
6106 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6107 BOOL oldVisible
= This
->bCursorVisible
;
6110 TRACE("(%p) : visible(%d)\n", This
, bShow
);
6113 * When ShowCursor is first called it should make the cursor appear at the OS's last
6114 * known cursor position. Because of this, some applications just repetitively call
6115 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6118 This
->xScreenSpace
= pt
.x
;
6119 This
->yScreenSpace
= pt
.y
;
6121 if (This
->haveHardwareCursor
) {
6122 This
->bCursorVisible
= bShow
;
6124 SetCursor(This
->hardwareCursor
);
6130 if (This
->cursorTexture
)
6131 This
->bCursorVisible
= bShow
;
6137 static HRESULT WINAPI
evict_managed_resource(IWineD3DResource
*resource
, void *data
) {
6138 TRACE("checking resource %p for eviction\n", resource
);
6139 if(((IWineD3DResourceImpl
*) resource
)->resource
.pool
== WINED3DPOOL_MANAGED
) {
6140 TRACE("Evicting %p\n", resource
);
6141 IWineD3DResource_UnLoad(resource
);
6143 IWineD3DResource_Release(resource
);
6147 static HRESULT WINAPI
IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice
* iface
) {
6148 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6149 TRACE("(%p)\n", This
);
6151 IWineD3DDevice_EnumResources(iface
, evict_managed_resource
, NULL
);
6155 static HRESULT
updateSurfaceDesc(IWineD3DSurfaceImpl
*surface
, const WINED3DPRESENT_PARAMETERS
* pPresentationParameters
)
6157 IWineD3DDeviceImpl
*device
= surface
->resource
.device
;
6158 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
6160 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6161 if(surface
->Flags
& SFLAG_DIBSECTION
) {
6162 /* Release the DC */
6163 SelectObject(surface
->hDC
, surface
->dib
.holdbitmap
);
6164 DeleteDC(surface
->hDC
);
6165 /* Release the DIB section */
6166 DeleteObject(surface
->dib
.DIBsection
);
6167 surface
->dib
.bitmap_data
= NULL
;
6168 surface
->resource
.allocatedMemory
= NULL
;
6169 surface
->Flags
&= ~SFLAG_DIBSECTION
;
6171 surface
->currentDesc
.Width
= pPresentationParameters
->BackBufferWidth
;
6172 surface
->currentDesc
.Height
= pPresentationParameters
->BackBufferHeight
;
6173 if (gl_info
->supported
[ARB_TEXTURE_NON_POWER_OF_TWO
] || gl_info
->supported
[ARB_TEXTURE_RECTANGLE
]
6174 || gl_info
->supported
[WINE_NORMALIZED_TEXRECT
])
6176 surface
->pow2Width
= pPresentationParameters
->BackBufferWidth
;
6177 surface
->pow2Height
= pPresentationParameters
->BackBufferHeight
;
6179 surface
->pow2Width
= surface
->pow2Height
= 1;
6180 while (surface
->pow2Width
< pPresentationParameters
->BackBufferWidth
) surface
->pow2Width
<<= 1;
6181 while (surface
->pow2Height
< pPresentationParameters
->BackBufferHeight
) surface
->pow2Height
<<= 1;
6183 surface
->glRect
.left
= 0;
6184 surface
->glRect
.top
= 0;
6185 surface
->glRect
.right
= surface
->pow2Width
;
6186 surface
->glRect
.bottom
= surface
->pow2Height
;
6188 if (surface
->texture_name
)
6190 struct wined3d_context
*context
= context_acquire(device
, NULL
, CTXUSAGE_RESOURCELOAD
);
6192 glDeleteTextures(1, &surface
->texture_name
);
6194 context_release(context
);
6195 surface
->texture_name
= 0;
6196 surface
->Flags
&= ~SFLAG_CLIENT
;
6198 if(surface
->pow2Width
!= pPresentationParameters
->BackBufferWidth
||
6199 surface
->pow2Height
!= pPresentationParameters
->BackBufferHeight
) {
6200 surface
->Flags
|= SFLAG_NONPOW2
;
6202 surface
->Flags
&= ~SFLAG_NONPOW2
;
6204 HeapFree(GetProcessHeap(), 0, surface
->resource
.heapMemory
);
6205 surface
->resource
.allocatedMemory
= NULL
;
6206 surface
->resource
.heapMemory
= NULL
;
6207 surface
->resource
.size
= IWineD3DSurface_GetPitch((IWineD3DSurface
*) surface
) * surface
->pow2Width
;
6209 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6211 if(!surface_init_sysmem((IWineD3DSurface
*) surface
))
6213 return E_OUTOFMEMORY
;
6218 static HRESULT WINAPI
reset_unload_resources(IWineD3DResource
*resource
, void *data
) {
6219 TRACE("Unloading resource %p\n", resource
);
6220 IWineD3DResource_UnLoad(resource
);
6221 IWineD3DResource_Release(resource
);
6225 static BOOL
is_display_mode_supported(IWineD3DDeviceImpl
*This
, const WINED3DPRESENT_PARAMETERS
*pp
)
6228 WINED3DDISPLAYMODE m
;
6231 /* All Windowed modes are supported, as is leaving the current mode */
6232 if(pp
->Windowed
) return TRUE
;
6233 if(!pp
->BackBufferWidth
) return TRUE
;
6234 if(!pp
->BackBufferHeight
) return TRUE
;
6236 count
= IWineD3D_GetAdapterModeCount(This
->wined3d
, This
->adapter
->ordinal
, WINED3DFMT_UNKNOWN
);
6237 for(i
= 0; i
< count
; i
++) {
6238 memset(&m
, 0, sizeof(m
));
6239 hr
= IWineD3D_EnumAdapterModes(This
->wined3d
, This
->adapter
->ordinal
, WINED3DFMT_UNKNOWN
, i
, &m
);
6241 ERR("EnumAdapterModes failed\n");
6243 if(m
.Width
== pp
->BackBufferWidth
&& m
.Height
== pp
->BackBufferHeight
) {
6244 /* Mode found, it is supported */
6248 /* Mode not found -> not supported */
6252 void delete_opengl_contexts(IWineD3DDevice
*iface
, IWineD3DSwapChain
*swapchain_iface
) {
6253 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6254 IWineD3DSwapChainImpl
*swapchain
= (IWineD3DSwapChainImpl
*) swapchain_iface
;
6255 const struct wined3d_gl_info
*gl_info
;
6256 struct wined3d_context
*context
;
6258 IWineD3DBaseShaderImpl
*shader
;
6260 context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
6261 gl_info
= context
->gl_info
;
6263 IWineD3DDevice_EnumResources(iface
, reset_unload_resources
, NULL
);
6264 LIST_FOR_EACH_ENTRY(shader
, &This
->shaders
, IWineD3DBaseShaderImpl
, baseShader
.shader_list_entry
) {
6265 This
->shader_backend
->shader_destroy((IWineD3DBaseShader
*) shader
);
6269 if(This
->depth_blt_texture
) {
6270 glDeleteTextures(1, &This
->depth_blt_texture
);
6271 This
->depth_blt_texture
= 0;
6273 if (This
->depth_blt_rb
) {
6274 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &This
->depth_blt_rb
);
6275 This
->depth_blt_rb
= 0;
6276 This
->depth_blt_rb_w
= 0;
6277 This
->depth_blt_rb_h
= 0;
6281 This
->blitter
->free_private(iface
);
6282 This
->frag_pipe
->free_private(iface
);
6283 This
->shader_backend
->shader_free_private(iface
);
6286 for (i
= 0; i
< This
->adapter
->gl_info
.limits
.textures
; ++i
)
6288 /* Textures are recreated below */
6289 glDeleteTextures(1, &This
->dummyTextureName
[i
]);
6290 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
6291 This
->dummyTextureName
[i
] = 0;
6295 context_release(context
);
6297 while (This
->numContexts
)
6299 context_destroy(This
, This
->contexts
[0]);
6301 HeapFree(GetProcessHeap(), 0, swapchain
->context
);
6302 swapchain
->context
= NULL
;
6303 swapchain
->num_contexts
= 0;
6306 HRESULT
create_primary_opengl_context(IWineD3DDevice
*iface
, IWineD3DSwapChain
*swapchain_iface
) {
6307 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6308 IWineD3DSwapChainImpl
*swapchain
= (IWineD3DSwapChainImpl
*) swapchain_iface
;
6310 IWineD3DSurfaceImpl
*target
;
6312 /* Recreate the primary swapchain's context */
6313 swapchain
->context
= HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain
->context
));
6314 if(swapchain
->backBuffer
) {
6315 target
= (IWineD3DSurfaceImpl
*) swapchain
->backBuffer
[0];
6317 target
= (IWineD3DSurfaceImpl
*) swapchain
->frontBuffer
;
6319 swapchain
->context
[0] = context_create(This
, target
, swapchain
->win_handle
, FALSE
, &swapchain
->presentParms
);
6320 swapchain
->num_contexts
= 1;
6321 swapchain
->context
[0]->render_offscreen
= swapchain
->render_to_fbo
;
6323 create_dummy_textures(This
);
6325 context_release(swapchain
->context
[0]);
6327 hr
= This
->shader_backend
->shader_alloc_private(iface
);
6329 ERR("Failed to recreate shader private data\n");
6332 hr
= This
->frag_pipe
->alloc_private(iface
);
6334 TRACE("Fragment pipeline private data couldn't be allocated\n");
6337 hr
= This
->blitter
->alloc_private(iface
);
6339 TRACE("Blitter private data couldn't be allocated\n");
6346 This
->blitter
->free_private(iface
);
6347 This
->frag_pipe
->free_private(iface
);
6348 This
->shader_backend
->shader_free_private(iface
);
6352 static HRESULT WINAPI
IWineD3DDeviceImpl_Reset(IWineD3DDevice
* iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
) {
6353 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6354 IWineD3DSwapChainImpl
*swapchain
;
6356 BOOL DisplayModeChanged
= FALSE
;
6357 WINED3DDISPLAYMODE mode
;
6358 TRACE("(%p)\n", This
);
6360 hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**) &swapchain
);
6362 ERR("Failed to get the first implicit swapchain\n");
6366 if(!is_display_mode_supported(This
, pPresentationParameters
)) {
6367 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6368 WARN("Requested mode: %d, %d\n", pPresentationParameters
->BackBufferWidth
,
6369 pPresentationParameters
->BackBufferHeight
);
6370 IWineD3DSwapChain_Release((IWineD3DSwapChain
*)swapchain
);
6371 return WINED3DERR_INVALIDCALL
;
6374 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6375 * on an existing gl context, so there's no real need for recreation.
6377 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6379 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6381 TRACE("New params:\n");
6382 TRACE("BackBufferWidth = %d\n", pPresentationParameters
->BackBufferWidth
);
6383 TRACE("BackBufferHeight = %d\n", pPresentationParameters
->BackBufferHeight
);
6384 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters
->BackBufferFormat
));
6385 TRACE("BackBufferCount = %d\n", pPresentationParameters
->BackBufferCount
);
6386 TRACE("MultiSampleType = %d\n", pPresentationParameters
->MultiSampleType
);
6387 TRACE("MultiSampleQuality = %d\n", pPresentationParameters
->MultiSampleQuality
);
6388 TRACE("SwapEffect = %d\n", pPresentationParameters
->SwapEffect
);
6389 TRACE("hDeviceWindow = %p\n", pPresentationParameters
->hDeviceWindow
);
6390 TRACE("Windowed = %s\n", pPresentationParameters
->Windowed
? "true" : "false");
6391 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters
->EnableAutoDepthStencil
? "true" : "false");
6392 TRACE("Flags = %08x\n", pPresentationParameters
->Flags
);
6393 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters
->FullScreen_RefreshRateInHz
);
6394 TRACE("PresentationInterval = %d\n", pPresentationParameters
->PresentationInterval
);
6396 /* No special treatment of these parameters. Just store them */
6397 swapchain
->presentParms
.SwapEffect
= pPresentationParameters
->SwapEffect
;
6398 swapchain
->presentParms
.Flags
= pPresentationParameters
->Flags
;
6399 swapchain
->presentParms
.PresentationInterval
= pPresentationParameters
->PresentationInterval
;
6400 swapchain
->presentParms
.FullScreen_RefreshRateInHz
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
6402 /* What to do about these? */
6403 if(pPresentationParameters
->BackBufferCount
!= 0 &&
6404 pPresentationParameters
->BackBufferCount
!= swapchain
->presentParms
.BackBufferCount
) {
6405 ERR("Cannot change the back buffer count yet\n");
6407 if(pPresentationParameters
->BackBufferFormat
!= WINED3DFMT_UNKNOWN
&&
6408 pPresentationParameters
->BackBufferFormat
!= swapchain
->presentParms
.BackBufferFormat
) {
6409 ERR("Cannot change the back buffer format yet\n");
6411 if(pPresentationParameters
->hDeviceWindow
!= NULL
&&
6412 pPresentationParameters
->hDeviceWindow
!= swapchain
->presentParms
.hDeviceWindow
) {
6413 ERR("Cannot change the device window yet\n");
6415 if (pPresentationParameters
->EnableAutoDepthStencil
&& !This
->auto_depth_stencil_buffer
) {
6418 TRACE("Creating the depth stencil buffer\n");
6420 hrc
= IWineD3DDeviceParent_CreateDepthStencilSurface(This
->device_parent
,
6422 pPresentationParameters
->BackBufferWidth
,
6423 pPresentationParameters
->BackBufferHeight
,
6424 pPresentationParameters
->AutoDepthStencilFormat
,
6425 pPresentationParameters
->MultiSampleType
,
6426 pPresentationParameters
->MultiSampleQuality
,
6428 &This
->auto_depth_stencil_buffer
);
6431 ERR("Failed to create the depth stencil buffer\n");
6432 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
6433 return WINED3DERR_INVALIDCALL
;
6437 /* Reset the depth stencil */
6438 if (pPresentationParameters
->EnableAutoDepthStencil
)
6439 IWineD3DDevice_SetDepthStencilSurface(iface
, This
->auto_depth_stencil_buffer
);
6441 IWineD3DDevice_SetDepthStencilSurface(iface
, NULL
);
6443 TRACE("Resetting stateblock\n");
6444 IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
);
6445 IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->stateBlock
);
6447 delete_opengl_contexts(iface
, (IWineD3DSwapChain
*) swapchain
);
6449 if(pPresentationParameters
->Windowed
) {
6450 mode
.Width
= swapchain
->orig_width
;
6451 mode
.Height
= swapchain
->orig_height
;
6452 mode
.RefreshRate
= 0;
6453 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
6455 mode
.Width
= pPresentationParameters
->BackBufferWidth
;
6456 mode
.Height
= pPresentationParameters
->BackBufferHeight
;
6457 mode
.RefreshRate
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
6458 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
6461 /* Should Width == 800 && Height == 0 set 800x600? */
6462 if(pPresentationParameters
->BackBufferWidth
!= 0 && pPresentationParameters
->BackBufferHeight
!= 0 &&
6463 (pPresentationParameters
->BackBufferWidth
!= swapchain
->presentParms
.BackBufferWidth
||
6464 pPresentationParameters
->BackBufferHeight
!= swapchain
->presentParms
.BackBufferHeight
))
6468 if(!pPresentationParameters
->Windowed
) {
6469 DisplayModeChanged
= TRUE
;
6471 swapchain
->presentParms
.BackBufferWidth
= pPresentationParameters
->BackBufferWidth
;
6472 swapchain
->presentParms
.BackBufferHeight
= pPresentationParameters
->BackBufferHeight
;
6474 hr
= updateSurfaceDesc((IWineD3DSurfaceImpl
*)swapchain
->frontBuffer
, pPresentationParameters
);
6477 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
6481 for(i
= 0; i
< swapchain
->presentParms
.BackBufferCount
; i
++) {
6482 hr
= updateSurfaceDesc((IWineD3DSurfaceImpl
*)swapchain
->backBuffer
[i
], pPresentationParameters
);
6485 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
6489 if(This
->auto_depth_stencil_buffer
) {
6490 hr
= updateSurfaceDesc((IWineD3DSurfaceImpl
*)This
->auto_depth_stencil_buffer
, pPresentationParameters
);
6493 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
6499 if((pPresentationParameters
->Windowed
&& !swapchain
->presentParms
.Windowed
) ||
6500 (swapchain
->presentParms
.Windowed
&& !pPresentationParameters
->Windowed
) ||
6501 DisplayModeChanged
) {
6503 IWineD3DDevice_SetDisplayMode(iface
, 0, &mode
);
6505 if(swapchain
->win_handle
&& !pPresentationParameters
->Windowed
) {
6506 if(swapchain
->presentParms
.Windowed
) {
6507 /* switch from windowed to fs */
6508 swapchain_setup_fullscreen_window(swapchain
, pPresentationParameters
->BackBufferWidth
,
6509 pPresentationParameters
->BackBufferHeight
);
6511 /* Fullscreen -> fullscreen mode change */
6512 MoveWindow(swapchain
->win_handle
, 0, 0,
6513 pPresentationParameters
->BackBufferWidth
, pPresentationParameters
->BackBufferHeight
,
6516 } else if(swapchain
->win_handle
&& !swapchain
->presentParms
.Windowed
) {
6517 /* Fullscreen -> windowed switch */
6518 swapchain_restore_fullscreen_window(swapchain
);
6520 swapchain
->presentParms
.Windowed
= pPresentationParameters
->Windowed
;
6521 } else if(!pPresentationParameters
->Windowed
) {
6522 DWORD style
= This
->style
, exStyle
= This
->exStyle
;
6523 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6524 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6525 * Reset to clear up their mess. Guild Wars also loses the device during that.
6529 swapchain_setup_fullscreen_window(swapchain
, pPresentationParameters
->BackBufferWidth
,
6530 pPresentationParameters
->BackBufferHeight
);
6531 This
->style
= style
;
6532 This
->exStyle
= exStyle
;
6535 /* Note: No parent needed for initial internal stateblock */
6536 hr
= IWineD3DDevice_CreateStateBlock(iface
, WINED3DSBT_INIT
, (IWineD3DStateBlock
**)&This
->stateBlock
, NULL
);
6537 if (FAILED(hr
)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr
);
6538 else TRACE("Created stateblock %p\n", This
->stateBlock
);
6539 This
->updateStateBlock
= This
->stateBlock
;
6540 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
6542 hr
= IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock
*) This
->stateBlock
);
6544 ERR("Resetting the stateblock failed with error 0x%08x\n", hr
);
6547 if(wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
)
6550 GetClientRect(swapchain
->win_handle
, &client_rect
);
6552 if(swapchain
->presentParms
.BackBufferWidth
!= client_rect
.right
||
6553 swapchain
->presentParms
.BackBufferHeight
!= client_rect
.bottom
)
6555 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6556 swapchain
->presentParms
.BackBufferWidth
,
6557 swapchain
->presentParms
.BackBufferHeight
,
6558 client_rect
.right
, client_rect
.bottom
);
6559 swapchain
->render_to_fbo
= TRUE
;
6563 TRACE("Rendering directly to GL_BACK\n");
6564 swapchain
->render_to_fbo
= FALSE
;
6568 hr
= create_primary_opengl_context(iface
, (IWineD3DSwapChain
*) swapchain
);
6569 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
6571 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6577 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice
*iface
, BOOL bEnableDialogs
) {
6578 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6579 /** FIXME: always true at the moment **/
6580 if(!bEnableDialogs
) {
6581 FIXME("(%p) Dialogs cannot be disabled yet\n", This
);
6587 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice
*iface
, WINED3DDEVICE_CREATION_PARAMETERS
*pParameters
) {
6588 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6589 TRACE("(%p) : pParameters %p\n", This
, pParameters
);
6591 *pParameters
= This
->createParms
;
6595 static void WINAPI
IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice
* iface
, UINT iSwapChain
, DWORD Flags
, CONST WINED3DGAMMARAMP
* pRamp
) {
6596 IWineD3DSwapChain
*swapchain
;
6598 TRACE("Relaying to swapchain\n");
6600 if (IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
) == WINED3D_OK
) {
6601 IWineD3DSwapChain_SetGammaRamp(swapchain
, Flags
, pRamp
);
6602 IWineD3DSwapChain_Release(swapchain
);
6607 static void WINAPI
IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DGAMMARAMP
* pRamp
) {
6608 IWineD3DSwapChain
*swapchain
;
6610 TRACE("Relaying to swapchain\n");
6612 if (IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
) == WINED3D_OK
) {
6613 IWineD3DSwapChain_GetGammaRamp(swapchain
, pRamp
);
6614 IWineD3DSwapChain_Release(swapchain
);
6620 /** ********************************************************
6621 * Notification functions
6622 ** ********************************************************/
6623 /** This function must be called in the release of a resource when ref == 0,
6624 * the contents of resource must still be correct,
6625 * any handles to other resource held by the caller must be closed
6626 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6627 *****************************************************/
6628 void device_resource_add(IWineD3DDeviceImpl
*This
, IWineD3DResource
*resource
)
6630 TRACE("(%p) : Adding resource %p\n", This
, resource
);
6632 list_add_head(&This
->resources
, &((IWineD3DResourceImpl
*) resource
)->resource
.resource_list_entry
);
6635 static void device_resource_remove(IWineD3DDeviceImpl
*This
, IWineD3DResource
*resource
)
6637 TRACE("(%p) : Removing resource %p\n", This
, resource
);
6639 list_remove(&((IWineD3DResourceImpl
*) resource
)->resource
.resource_list_entry
);
6642 void device_resource_released(IWineD3DDeviceImpl
*This
, IWineD3DResource
*resource
)
6644 WINED3DRESOURCETYPE type
= IWineD3DResource_GetType(resource
);
6647 TRACE("(%p) : resource %p\n", This
, resource
);
6649 context_resource_released((IWineD3DDevice
*)This
, resource
, type
);
6652 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6653 case WINED3DRTYPE_SURFACE
: {
6656 if (This
->d3d_initialized
)
6658 for (i
= 0; i
< This
->adapter
->gl_info
.limits
.buffers
; ++i
)
6660 if (This
->render_targets
[i
] == (IWineD3DSurface
*)resource
) {
6661 This
->render_targets
[i
] = NULL
;
6664 if (This
->stencilBufferTarget
== (IWineD3DSurface
*)resource
) {
6665 This
->stencilBufferTarget
= NULL
;
6671 case WINED3DRTYPE_TEXTURE
:
6672 case WINED3DRTYPE_CUBETEXTURE
:
6673 case WINED3DRTYPE_VOLUMETEXTURE
:
6674 for (counter
= 0; counter
< MAX_COMBINED_SAMPLERS
; counter
++) {
6675 if (This
->stateBlock
!= NULL
&& This
->stateBlock
->textures
[counter
] == (IWineD3DBaseTexture
*)resource
) {
6676 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter
, resource
);
6677 This
->stateBlock
->textures
[counter
] = NULL
;
6679 if (This
->updateStateBlock
!= This
->stateBlock
){
6680 if (This
->updateStateBlock
->textures
[counter
] == (IWineD3DBaseTexture
*)resource
) {
6681 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter
, resource
);
6682 This
->updateStateBlock
->textures
[counter
] = NULL
;
6687 case WINED3DRTYPE_VOLUME
:
6688 /* TODO: nothing really? */
6690 case WINED3DRTYPE_BUFFER
:
6693 TRACE("Cleaning up stream pointers\n");
6695 for(streamNumber
= 0; streamNumber
< MAX_STREAMS
; streamNumber
++){
6696 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6697 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6699 if (This
->updateStateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
6700 if ((IWineD3DResource
*)This
->updateStateBlock
->streamSource
[streamNumber
] == resource
) {
6701 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber
);
6702 This
->updateStateBlock
->streamSource
[streamNumber
] = 0;
6703 /* Set changed flag? */
6706 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) */
6707 if ((IWineD3DResource
*)This
->stateBlock
->streamSource
[streamNumber
] == resource
) {
6708 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber
);
6709 This
->stateBlock
->streamSource
[streamNumber
] = 0;
6714 if (This
->updateStateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
6715 if (This
->updateStateBlock
->pIndexData
== (IWineD3DBuffer
*)resource
) {
6716 This
->updateStateBlock
->pIndexData
= NULL
;
6719 if (This
->stateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
6720 if (This
->stateBlock
->pIndexData
== (IWineD3DBuffer
*)resource
) {
6721 This
->stateBlock
->pIndexData
= NULL
;
6728 FIXME("(%p) unknown resource type %p %u\n", This
, resource
, IWineD3DResource_GetType(resource
));
6733 /* Remove the resource from the resourceStore */
6734 device_resource_remove(This
, resource
);
6736 TRACE("Resource released\n");
6740 static HRESULT WINAPI
IWineD3DDeviceImpl_EnumResources(IWineD3DDevice
*iface
, D3DCB_ENUMRESOURCES pCallback
, void *pData
) {
6741 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6742 IWineD3DResourceImpl
*resource
, *cursor
;
6744 TRACE("(%p)->(%p,%p)\n", This
, pCallback
, pData
);
6746 LIST_FOR_EACH_ENTRY_SAFE(resource
, cursor
, &This
->resources
, IWineD3DResourceImpl
, resource
.resource_list_entry
) {
6747 TRACE("enumerating resource %p\n", resource
);
6748 IWineD3DResource_AddRef((IWineD3DResource
*) resource
);
6749 ret
= pCallback((IWineD3DResource
*) resource
, pData
);
6750 if(ret
== S_FALSE
) {
6751 TRACE("Canceling enumeration\n");
6758 /**********************************************************
6759 * IWineD3DDevice VTbl follows
6760 **********************************************************/
6762 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl
=
6764 /*** IUnknown methods ***/
6765 IWineD3DDeviceImpl_QueryInterface
,
6766 IWineD3DDeviceImpl_AddRef
,
6767 IWineD3DDeviceImpl_Release
,
6768 /*** IWineD3DDevice methods ***/
6769 IWineD3DDeviceImpl_GetParent
,
6770 /*** Creation methods**/
6771 IWineD3DDeviceImpl_CreateBuffer
,
6772 IWineD3DDeviceImpl_CreateVertexBuffer
,
6773 IWineD3DDeviceImpl_CreateIndexBuffer
,
6774 IWineD3DDeviceImpl_CreateStateBlock
,
6775 IWineD3DDeviceImpl_CreateSurface
,
6776 IWineD3DDeviceImpl_CreateRendertargetView
,
6777 IWineD3DDeviceImpl_CreateTexture
,
6778 IWineD3DDeviceImpl_CreateVolumeTexture
,
6779 IWineD3DDeviceImpl_CreateVolume
,
6780 IWineD3DDeviceImpl_CreateCubeTexture
,
6781 IWineD3DDeviceImpl_CreateQuery
,
6782 IWineD3DDeviceImpl_CreateSwapChain
,
6783 IWineD3DDeviceImpl_CreateVertexDeclaration
,
6784 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF
,
6785 IWineD3DDeviceImpl_CreateVertexShader
,
6786 IWineD3DDeviceImpl_CreatePixelShader
,
6787 IWineD3DDeviceImpl_CreatePalette
,
6788 /*** Odd functions **/
6789 IWineD3DDeviceImpl_Init3D
,
6790 IWineD3DDeviceImpl_InitGDI
,
6791 IWineD3DDeviceImpl_Uninit3D
,
6792 IWineD3DDeviceImpl_UninitGDI
,
6793 IWineD3DDeviceImpl_SetMultithreaded
,
6794 IWineD3DDeviceImpl_EvictManagedResources
,
6795 IWineD3DDeviceImpl_GetAvailableTextureMem
,
6796 IWineD3DDeviceImpl_GetBackBuffer
,
6797 IWineD3DDeviceImpl_GetCreationParameters
,
6798 IWineD3DDeviceImpl_GetDeviceCaps
,
6799 IWineD3DDeviceImpl_GetDirect3D
,
6800 IWineD3DDeviceImpl_GetDisplayMode
,
6801 IWineD3DDeviceImpl_SetDisplayMode
,
6802 IWineD3DDeviceImpl_GetNumberOfSwapChains
,
6803 IWineD3DDeviceImpl_GetRasterStatus
,
6804 IWineD3DDeviceImpl_GetSwapChain
,
6805 IWineD3DDeviceImpl_Reset
,
6806 IWineD3DDeviceImpl_SetDialogBoxMode
,
6807 IWineD3DDeviceImpl_SetCursorProperties
,
6808 IWineD3DDeviceImpl_SetCursorPosition
,
6809 IWineD3DDeviceImpl_ShowCursor
,
6810 /*** Getters and setters **/
6811 IWineD3DDeviceImpl_SetClipPlane
,
6812 IWineD3DDeviceImpl_GetClipPlane
,
6813 IWineD3DDeviceImpl_SetClipStatus
,
6814 IWineD3DDeviceImpl_GetClipStatus
,
6815 IWineD3DDeviceImpl_SetCurrentTexturePalette
,
6816 IWineD3DDeviceImpl_GetCurrentTexturePalette
,
6817 IWineD3DDeviceImpl_SetDepthStencilSurface
,
6818 IWineD3DDeviceImpl_GetDepthStencilSurface
,
6819 IWineD3DDeviceImpl_SetGammaRamp
,
6820 IWineD3DDeviceImpl_GetGammaRamp
,
6821 IWineD3DDeviceImpl_SetIndexBuffer
,
6822 IWineD3DDeviceImpl_GetIndexBuffer
,
6823 IWineD3DDeviceImpl_SetBaseVertexIndex
,
6824 IWineD3DDeviceImpl_GetBaseVertexIndex
,
6825 IWineD3DDeviceImpl_SetLight
,
6826 IWineD3DDeviceImpl_GetLight
,
6827 IWineD3DDeviceImpl_SetLightEnable
,
6828 IWineD3DDeviceImpl_GetLightEnable
,
6829 IWineD3DDeviceImpl_SetMaterial
,
6830 IWineD3DDeviceImpl_GetMaterial
,
6831 IWineD3DDeviceImpl_SetNPatchMode
,
6832 IWineD3DDeviceImpl_GetNPatchMode
,
6833 IWineD3DDeviceImpl_SetPaletteEntries
,
6834 IWineD3DDeviceImpl_GetPaletteEntries
,
6835 IWineD3DDeviceImpl_SetPixelShader
,
6836 IWineD3DDeviceImpl_GetPixelShader
,
6837 IWineD3DDeviceImpl_SetPixelShaderConstantB
,
6838 IWineD3DDeviceImpl_GetPixelShaderConstantB
,
6839 IWineD3DDeviceImpl_SetPixelShaderConstantI
,
6840 IWineD3DDeviceImpl_GetPixelShaderConstantI
,
6841 IWineD3DDeviceImpl_SetPixelShaderConstantF
,
6842 IWineD3DDeviceImpl_GetPixelShaderConstantF
,
6843 IWineD3DDeviceImpl_SetRenderState
,
6844 IWineD3DDeviceImpl_GetRenderState
,
6845 IWineD3DDeviceImpl_SetRenderTarget
,
6846 IWineD3DDeviceImpl_GetRenderTarget
,
6847 IWineD3DDeviceImpl_SetFrontBackBuffers
,
6848 IWineD3DDeviceImpl_SetSamplerState
,
6849 IWineD3DDeviceImpl_GetSamplerState
,
6850 IWineD3DDeviceImpl_SetScissorRect
,
6851 IWineD3DDeviceImpl_GetScissorRect
,
6852 IWineD3DDeviceImpl_SetSoftwareVertexProcessing
,
6853 IWineD3DDeviceImpl_GetSoftwareVertexProcessing
,
6854 IWineD3DDeviceImpl_SetStreamSource
,
6855 IWineD3DDeviceImpl_GetStreamSource
,
6856 IWineD3DDeviceImpl_SetStreamSourceFreq
,
6857 IWineD3DDeviceImpl_GetStreamSourceFreq
,
6858 IWineD3DDeviceImpl_SetTexture
,
6859 IWineD3DDeviceImpl_GetTexture
,
6860 IWineD3DDeviceImpl_SetTextureStageState
,
6861 IWineD3DDeviceImpl_GetTextureStageState
,
6862 IWineD3DDeviceImpl_SetTransform
,
6863 IWineD3DDeviceImpl_GetTransform
,
6864 IWineD3DDeviceImpl_SetVertexDeclaration
,
6865 IWineD3DDeviceImpl_GetVertexDeclaration
,
6866 IWineD3DDeviceImpl_SetVertexShader
,
6867 IWineD3DDeviceImpl_GetVertexShader
,
6868 IWineD3DDeviceImpl_SetVertexShaderConstantB
,
6869 IWineD3DDeviceImpl_GetVertexShaderConstantB
,
6870 IWineD3DDeviceImpl_SetVertexShaderConstantI
,
6871 IWineD3DDeviceImpl_GetVertexShaderConstantI
,
6872 IWineD3DDeviceImpl_SetVertexShaderConstantF
,
6873 IWineD3DDeviceImpl_GetVertexShaderConstantF
,
6874 IWineD3DDeviceImpl_SetViewport
,
6875 IWineD3DDeviceImpl_GetViewport
,
6876 IWineD3DDeviceImpl_MultiplyTransform
,
6877 IWineD3DDeviceImpl_ValidateDevice
,
6878 IWineD3DDeviceImpl_ProcessVertices
,
6879 /*** State block ***/
6880 IWineD3DDeviceImpl_BeginStateBlock
,
6881 IWineD3DDeviceImpl_EndStateBlock
,
6882 /*** Scene management ***/
6883 IWineD3DDeviceImpl_BeginScene
,
6884 IWineD3DDeviceImpl_EndScene
,
6885 IWineD3DDeviceImpl_Present
,
6886 IWineD3DDeviceImpl_Clear
,
6887 IWineD3DDeviceImpl_ClearRendertargetView
,
6889 IWineD3DDeviceImpl_SetPrimitiveType
,
6890 IWineD3DDeviceImpl_GetPrimitiveType
,
6891 IWineD3DDeviceImpl_DrawPrimitive
,
6892 IWineD3DDeviceImpl_DrawIndexedPrimitive
,
6893 IWineD3DDeviceImpl_DrawPrimitiveUP
,
6894 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP
,
6895 IWineD3DDeviceImpl_DrawPrimitiveStrided
,
6896 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided
,
6897 IWineD3DDeviceImpl_DrawRectPatch
,
6898 IWineD3DDeviceImpl_DrawTriPatch
,
6899 IWineD3DDeviceImpl_DeletePatch
,
6900 IWineD3DDeviceImpl_ColorFill
,
6901 IWineD3DDeviceImpl_UpdateTexture
,
6902 IWineD3DDeviceImpl_UpdateSurface
,
6903 IWineD3DDeviceImpl_GetFrontBufferData
,
6904 /*** object tracking ***/
6905 IWineD3DDeviceImpl_EnumResources
6908 HRESULT
device_init(IWineD3DDeviceImpl
*device
, IWineD3DImpl
*wined3d
,
6909 UINT adapter_idx
, WINED3DDEVTYPE device_type
, HWND focus_window
, DWORD flags
,
6910 IUnknown
*parent
, IWineD3DDeviceParent
*device_parent
)
6912 struct wined3d_adapter
*adapter
= &wined3d
->adapters
[adapter_idx
];
6913 const struct fragment_pipeline
*fragment_pipeline
;
6914 struct shader_caps shader_caps
;
6915 struct fragment_caps ffp_caps
;
6916 WINED3DDISPLAYMODE mode
;
6920 device
->lpVtbl
= &IWineD3DDevice_Vtbl
;
6922 device
->wined3d
= (IWineD3D
*)wined3d
;
6923 IWineD3D_AddRef(device
->wined3d
);
6924 device
->adapter
= wined3d
->adapter_count
? adapter
: NULL
;
6925 device
->parent
= parent
;
6926 device
->device_parent
= device_parent
;
6927 list_init(&device
->resources
);
6928 list_init(&device
->shaders
);
6930 device
->surface_alignment
= wined3d
->dxVersion
== 7 ? DDRAW_PITCH_ALIGNMENT
: D3D8_PITCH_ALIGNMENT
;
6931 device
->posFixup
[0] = 1.0f
; /* This is needed to get the x coord unmodified through a MAD. */
6933 /* Get the initial screen setup for ddraw. */
6934 hr
= IWineD3D_GetAdapterDisplayMode((IWineD3D
*)wined3d
, adapter_idx
, &mode
);
6937 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr
);
6938 IWineD3D_Release(device
->wined3d
);
6941 device
->ddraw_width
= mode
.Width
;
6942 device
->ddraw_height
= mode
.Height
;
6943 device
->ddraw_format
= mode
.Format
;
6945 /* Save the creation parameters. */
6946 device
->createParms
.AdapterOrdinal
= adapter_idx
;
6947 device
->createParms
.DeviceType
= device_type
;
6948 device
->createParms
.hFocusWindow
= focus_window
;
6949 device
->createParms
.BehaviorFlags
= flags
;
6951 device
->devType
= device_type
;
6952 for (i
= 0; i
< PATCHMAP_SIZE
; ++i
) list_init(&device
->patches
[i
]);
6954 select_shader_mode(&adapter
->gl_info
, &device
->ps_selected_mode
, &device
->vs_selected_mode
);
6955 device
->shader_backend
= select_shader_backend(adapter
, device_type
);
6957 memset(&shader_caps
, 0, sizeof(shader_caps
));
6958 device
->shader_backend
->shader_get_caps(device_type
, &adapter
->gl_info
, &shader_caps
);
6959 device
->d3d_vshader_constantF
= shader_caps
.MaxVertexShaderConst
;
6960 device
->d3d_pshader_constantF
= shader_caps
.MaxPixelShaderConst
;
6961 device
->vs_clipping
= shader_caps
.VSClipping
;
6963 memset(&ffp_caps
, 0, sizeof(ffp_caps
));
6964 fragment_pipeline
= select_fragment_implementation(adapter
, device_type
);
6965 device
->frag_pipe
= fragment_pipeline
;
6966 fragment_pipeline
->get_caps(device_type
, &adapter
->gl_info
, &ffp_caps
);
6967 device
->max_ffp_textures
= ffp_caps
.MaxSimultaneousTextures
;
6968 device
->max_ffp_texture_stages
= ffp_caps
.MaxTextureBlendStages
;
6970 hr
= compile_state_table(device
->StateTable
, device
->multistate_funcs
, &adapter
->gl_info
,
6971 ffp_vertexstate_template
, fragment_pipeline
, misc_state_template
);
6974 ERR("Failed to compile state table, hr %#x.\n", hr
);
6975 IWineD3D_Release(device
->wined3d
);
6979 device
->blitter
= select_blit_implementation(adapter
, device_type
);
6985 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl
*This
, DWORD state
) {
6986 DWORD rep
= This
->StateTable
[state
].representative
;
6987 struct wined3d_context
*context
;
6992 for(i
= 0; i
< This
->numContexts
; i
++) {
6993 context
= This
->contexts
[i
];
6994 if(isStateDirty(context
, rep
)) continue;
6996 context
->dirtyArray
[context
->numDirtyEntries
++] = rep
;
6999 context
->isStateDirty
[idx
] |= (1 << shift
);
7003 void get_drawable_size_pbuffer(struct wined3d_context
*context
, UINT
*width
, UINT
*height
)
7005 IWineD3DDeviceImpl
*device
= ((IWineD3DSurfaceImpl
*)context
->current_rt
)->resource
.device
;
7006 /* The drawable size of a pbuffer render target is the current pbuffer size. */
7007 *width
= device
->pbufferWidth
;
7008 *height
= device
->pbufferHeight
;
7011 void get_drawable_size_fbo(struct wined3d_context
*context
, UINT
*width
, UINT
*height
)
7013 IWineD3DSurfaceImpl
*surface
= (IWineD3DSurfaceImpl
*)context
->current_rt
;
7014 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7015 *width
= surface
->pow2Width
;
7016 *height
= surface
->pow2Height
;
7019 void get_drawable_size_backbuffer(struct wined3d_context
*context
, UINT
*width
, UINT
*height
)
7021 IWineD3DSurfaceImpl
*surface
= (IWineD3DSurfaceImpl
*)context
->surface
;
7022 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7023 * current context's drawable, which is the size of the back buffer of the swapchain
7024 * the active context belongs to. The back buffer of the swapchain is stored as the
7025 * surface the context belongs to. */
7026 *width
= surface
->currentDesc
.Width
;
7027 *height
= surface
->currentDesc
.Height
;