2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
12 * Copyright 2009 Henri Verbeet for CodeWeavers
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
34 #include "wined3d_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(d3d
);
37 #define GLINFO_LOCATION This->adapter->gl_info
39 /* Define the default light parameters as specified by MSDN */
40 const WINED3DLIGHT WINED3D_default_light
= {
42 WINED3DLIGHT_DIRECTIONAL
, /* Type */
43 { 1.0f
, 1.0f
, 1.0f
, 0.0f
}, /* Diffuse r,g,b,a */
44 { 0.0f
, 0.0f
, 0.0f
, 0.0f
}, /* Specular r,g,b,a */
45 { 0.0f
, 0.0f
, 0.0f
, 0.0f
}, /* Ambient r,g,b,a, */
46 { 0.0f
, 0.0f
, 0.0f
}, /* Position x,y,z */
47 { 0.0f
, 0.0f
, 1.0f
}, /* Direction x,y,z */
50 0.0f
, 0.0f
, 0.0f
, /* Attenuation 0,1,2 */
55 /**********************************************************
56 * Global variable / Constants follow
57 **********************************************************/
58 const float identity
[] =
60 1.0f
, 0.0f
, 0.0f
, 0.0f
,
61 0.0f
, 1.0f
, 0.0f
, 0.0f
,
62 0.0f
, 0.0f
, 1.0f
, 0.0f
,
63 0.0f
, 0.0f
, 0.0f
, 1.0f
,
64 }; /* When needed for comparisons */
66 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
67 * actually have the same values in GL and D3D. */
68 static GLenum
gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type
)
70 switch(primitive_type
)
72 case WINED3DPT_POINTLIST
:
75 case WINED3DPT_LINELIST
:
78 case WINED3DPT_LINESTRIP
:
81 case WINED3DPT_TRIANGLELIST
:
84 case WINED3DPT_TRIANGLESTRIP
:
85 return GL_TRIANGLE_STRIP
;
87 case WINED3DPT_TRIANGLEFAN
:
88 return GL_TRIANGLE_FAN
;
90 case WINED3DPT_LINELIST_ADJ
:
91 return GL_LINES_ADJACENCY_ARB
;
93 case WINED3DPT_LINESTRIP_ADJ
:
94 return GL_LINE_STRIP_ADJACENCY_ARB
;
96 case WINED3DPT_TRIANGLELIST_ADJ
:
97 return GL_TRIANGLES_ADJACENCY_ARB
;
99 case WINED3DPT_TRIANGLESTRIP_ADJ
:
100 return GL_TRIANGLE_STRIP_ADJACENCY_ARB
;
103 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type
));
108 static WINED3DPRIMITIVETYPE
d3d_primitive_type_from_gl(GLenum primitive_type
)
110 switch(primitive_type
)
113 return WINED3DPT_POINTLIST
;
116 return WINED3DPT_LINELIST
;
119 return WINED3DPT_LINESTRIP
;
122 return WINED3DPT_TRIANGLELIST
;
124 case GL_TRIANGLE_STRIP
:
125 return WINED3DPT_TRIANGLESTRIP
;
127 case GL_TRIANGLE_FAN
:
128 return WINED3DPT_TRIANGLEFAN
;
130 case GL_LINES_ADJACENCY_ARB
:
131 return WINED3DPT_LINELIST_ADJ
;
133 case GL_LINE_STRIP_ADJACENCY_ARB
:
134 return WINED3DPT_LINESTRIP_ADJ
;
136 case GL_TRIANGLES_ADJACENCY_ARB
:
137 return WINED3DPT_TRIANGLELIST_ADJ
;
139 case GL_TRIANGLE_STRIP_ADJACENCY_ARB
:
140 return WINED3DPT_TRIANGLESTRIP_ADJ
;
143 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type
));
144 return WINED3DPT_UNDEFINED
;
148 static BOOL
fixed_get_input(BYTE usage
, BYTE usage_idx
, unsigned int *regnum
)
150 if ((usage
== WINED3DDECLUSAGE_POSITION
|| usage
== WINED3DDECLUSAGE_POSITIONT
) && usage_idx
== 0)
151 *regnum
= WINED3D_FFP_POSITION
;
152 else if (usage
== WINED3DDECLUSAGE_BLENDWEIGHT
&& usage_idx
== 0)
153 *regnum
= WINED3D_FFP_BLENDWEIGHT
;
154 else if (usage
== WINED3DDECLUSAGE_BLENDINDICES
&& usage_idx
== 0)
155 *regnum
= WINED3D_FFP_BLENDINDICES
;
156 else if (usage
== WINED3DDECLUSAGE_NORMAL
&& usage_idx
== 0)
157 *regnum
= WINED3D_FFP_NORMAL
;
158 else if (usage
== WINED3DDECLUSAGE_PSIZE
&& usage_idx
== 0)
159 *regnum
= WINED3D_FFP_PSIZE
;
160 else if (usage
== WINED3DDECLUSAGE_COLOR
&& usage_idx
== 0)
161 *regnum
= WINED3D_FFP_DIFFUSE
;
162 else if (usage
== WINED3DDECLUSAGE_COLOR
&& usage_idx
== 1)
163 *regnum
= WINED3D_FFP_SPECULAR
;
164 else if (usage
== WINED3DDECLUSAGE_TEXCOORD
&& usage_idx
< WINED3DDP_MAXTEXCOORD
)
165 *regnum
= WINED3D_FFP_TEXCOORD0
+ usage_idx
;
168 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage
), usage_idx
);
176 /* Context activation is done by the caller. */
177 void device_stream_info_from_declaration(IWineD3DDeviceImpl
*This
,
178 BOOL use_vshader
, struct wined3d_stream_info
*stream_info
, BOOL
*fixup
)
180 /* We need to deal with frequency data! */
181 IWineD3DVertexDeclarationImpl
*declaration
= (IWineD3DVertexDeclarationImpl
*)This
->stateBlock
->vertexDecl
;
184 stream_info
->use_map
= 0;
185 stream_info
->swizzle_map
= 0;
187 /* Check for transformed vertices, disable vertex shader if present. */
188 stream_info
->position_transformed
= declaration
->position_transformed
;
189 if (declaration
->position_transformed
) use_vshader
= FALSE
;
191 /* Translate the declaration into strided data. */
192 for (i
= 0; i
< declaration
->element_count
; ++i
)
194 const struct wined3d_vertex_declaration_element
*element
= &declaration
->elements
[i
];
195 GLuint buffer_object
= 0;
196 const BYTE
*data
= NULL
;
201 TRACE("%p Element %p (%u of %u)\n", declaration
->elements
,
202 element
, i
+ 1, declaration
->element_count
);
204 if (!This
->stateBlock
->streamSource
[element
->input_slot
]) continue;
206 stride
= This
->stateBlock
->streamStride
[element
->input_slot
];
207 if (This
->stateBlock
->streamIsUP
)
209 TRACE("Stream %u is UP, %p\n", element
->input_slot
, This
->stateBlock
->streamSource
[element
->input_slot
]);
211 data
= (BYTE
*)This
->stateBlock
->streamSource
[element
->input_slot
];
215 TRACE("Stream %u isn't UP, %p\n", element
->input_slot
, This
->stateBlock
->streamSource
[element
->input_slot
]);
216 data
= buffer_get_memory(This
->stateBlock
->streamSource
[element
->input_slot
], &buffer_object
);
218 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
219 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
220 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
221 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
222 * not, drawStridedSlow is needed, including a vertex buffer path. */
223 if (This
->stateBlock
->loadBaseVertexIndex
< 0)
225 WARN("loadBaseVertexIndex is < 0 (%d), not using vbos\n", This
->stateBlock
->loadBaseVertexIndex
);
227 data
= buffer_get_sysmem((struct wined3d_buffer
*)This
->stateBlock
->streamSource
[element
->input_slot
]);
228 if ((UINT_PTR
)data
< -This
->stateBlock
->loadBaseVertexIndex
* stride
)
230 FIXME("System memory vertex data load offset is negative!\n");
236 if (buffer_object
) *fixup
= TRUE
;
237 else if (*fixup
&& !use_vshader
238 && (element
->usage
== WINED3DDECLUSAGE_COLOR
239 || element
->usage
== WINED3DDECLUSAGE_POSITIONT
))
241 static BOOL warned
= FALSE
;
244 /* This may be bad with the fixed function pipeline. */
245 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
251 data
+= element
->offset
;
253 TRACE("offset %u input_slot %u usage_idx %d\n", element
->offset
, element
->input_slot
, element
->usage_idx
);
257 if (element
->output_slot
== ~0U)
259 /* TODO: Assuming vertexdeclarations are usually used with the
260 * same or a similar shader, it might be worth it to store the
261 * last used output slot and try that one first. */
262 stride_used
= vshader_get_input(This
->stateBlock
->vertexShader
,
263 element
->usage
, element
->usage_idx
, &idx
);
267 idx
= element
->output_slot
;
273 if (!element
->ffp_valid
)
275 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
276 debug_d3dformat(element
->format_desc
->format
), debug_d3ddeclusage(element
->usage
));
281 stride_used
= fixed_get_input(element
->usage
, element
->usage_idx
, &idx
);
287 TRACE("Load %s array %u [usage %s, usage_idx %u, "
288 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
289 use_vshader
? "shader": "fixed function", idx
,
290 debug_d3ddeclusage(element
->usage
), element
->usage_idx
, element
->input_slot
,
291 element
->offset
, stride
, debug_d3dformat(element
->format_desc
->format
), buffer_object
);
293 stream_info
->elements
[idx
].format_desc
= element
->format_desc
;
294 stream_info
->elements
[idx
].stride
= stride
;
295 stream_info
->elements
[idx
].data
= data
;
296 stream_info
->elements
[idx
].stream_idx
= element
->input_slot
;
297 stream_info
->elements
[idx
].buffer_object
= buffer_object
;
299 if (!This
->adapter
->gl_info
.supported
[ARB_VERTEX_ARRAY_BGRA
]
300 && element
->format_desc
->format
== WINED3DFMT_B8G8R8A8_UNORM
)
302 stream_info
->swizzle_map
|= 1 << idx
;
304 stream_info
->use_map
|= 1 << idx
;
308 This
->num_buffer_queries
= 0;
309 if (!This
->stateBlock
->streamIsUP
)
311 WORD map
= stream_info
->use_map
;
313 /* PreLoad all the vertex buffers. */
314 for (i
= 0; map
; map
>>= 1, ++i
)
316 struct wined3d_stream_info_element
*element
;
317 struct wined3d_buffer
*buffer
;
318 struct wined3d_event_query
*query
;
320 if (!(map
& 1)) continue;
322 element
= &stream_info
->elements
[i
];
323 buffer
= (struct wined3d_buffer
*)This
->stateBlock
->streamSource
[element
->stream_idx
];
324 IWineD3DBuffer_PreLoad((IWineD3DBuffer
*)buffer
);
326 /* If PreLoad dropped the buffer object, update the stream info. */
327 if (buffer
->buffer_object
!= element
->buffer_object
)
329 element
->buffer_object
= 0;
330 element
->data
= buffer_get_sysmem(buffer
) + (ptrdiff_t)element
->data
;
333 query
= ((struct wined3d_buffer
*) buffer
)->query
;
336 This
->buffer_queries
[This
->num_buffer_queries
++] = query
;
342 static void stream_info_element_from_strided(const struct wined3d_gl_info
*gl_info
,
343 const struct WineDirect3DStridedData
*strided
, struct wined3d_stream_info_element
*e
)
345 const struct wined3d_format_desc
*format_desc
= getFormatDescEntry(strided
->format
, gl_info
);
346 e
->format_desc
= format_desc
;
347 e
->stride
= strided
->dwStride
;
348 e
->data
= strided
->lpData
;
350 e
->buffer_object
= 0;
353 static void device_stream_info_from_strided(const struct wined3d_gl_info
*gl_info
,
354 const struct WineDirect3DVertexStridedData
*strided
, struct wined3d_stream_info
*stream_info
)
358 memset(stream_info
, 0, sizeof(*stream_info
));
360 if (strided
->position
.lpData
)
361 stream_info_element_from_strided(gl_info
, &strided
->position
, &stream_info
->elements
[WINED3D_FFP_POSITION
]);
362 if (strided
->normal
.lpData
)
363 stream_info_element_from_strided(gl_info
, &strided
->normal
, &stream_info
->elements
[WINED3D_FFP_NORMAL
]);
364 if (strided
->diffuse
.lpData
)
365 stream_info_element_from_strided(gl_info
, &strided
->diffuse
, &stream_info
->elements
[WINED3D_FFP_DIFFUSE
]);
366 if (strided
->specular
.lpData
)
367 stream_info_element_from_strided(gl_info
, &strided
->specular
, &stream_info
->elements
[WINED3D_FFP_SPECULAR
]);
369 for (i
= 0; i
< WINED3DDP_MAXTEXCOORD
; ++i
)
371 if (strided
->texCoords
[i
].lpData
)
372 stream_info_element_from_strided(gl_info
, &strided
->texCoords
[i
],
373 &stream_info
->elements
[WINED3D_FFP_TEXCOORD0
+ i
]);
376 stream_info
->position_transformed
= strided
->position_transformed
;
378 for (i
= 0; i
< sizeof(stream_info
->elements
) / sizeof(*stream_info
->elements
); ++i
)
380 if (!stream_info
->elements
[i
].format_desc
) continue;
382 if (!gl_info
->supported
[ARB_VERTEX_ARRAY_BGRA
]
383 && stream_info
->elements
[i
].format_desc
->format
== WINED3DFMT_B8G8R8A8_UNORM
)
385 stream_info
->swizzle_map
|= 1 << i
;
387 stream_info
->use_map
|= 1 << i
;
391 static void device_trace_strided_stream_info(const struct wined3d_stream_info
*stream_info
)
393 TRACE("Strided Data:\n");
394 TRACE_STRIDED(stream_info
, WINED3D_FFP_POSITION
);
395 TRACE_STRIDED(stream_info
, WINED3D_FFP_BLENDWEIGHT
);
396 TRACE_STRIDED(stream_info
, WINED3D_FFP_BLENDINDICES
);
397 TRACE_STRIDED(stream_info
, WINED3D_FFP_NORMAL
);
398 TRACE_STRIDED(stream_info
, WINED3D_FFP_PSIZE
);
399 TRACE_STRIDED(stream_info
, WINED3D_FFP_DIFFUSE
);
400 TRACE_STRIDED(stream_info
, WINED3D_FFP_SPECULAR
);
401 TRACE_STRIDED(stream_info
, WINED3D_FFP_TEXCOORD0
);
402 TRACE_STRIDED(stream_info
, WINED3D_FFP_TEXCOORD1
);
403 TRACE_STRIDED(stream_info
, WINED3D_FFP_TEXCOORD2
);
404 TRACE_STRIDED(stream_info
, WINED3D_FFP_TEXCOORD3
);
405 TRACE_STRIDED(stream_info
, WINED3D_FFP_TEXCOORD4
);
406 TRACE_STRIDED(stream_info
, WINED3D_FFP_TEXCOORD5
);
407 TRACE_STRIDED(stream_info
, WINED3D_FFP_TEXCOORD6
);
408 TRACE_STRIDED(stream_info
, WINED3D_FFP_TEXCOORD7
);
411 /* Context activation is done by the caller. */
412 void device_update_stream_info(IWineD3DDeviceImpl
*device
, const struct wined3d_gl_info
*gl_info
)
414 struct wined3d_stream_info
*stream_info
= &device
->strided_streams
;
415 IWineD3DStateBlockImpl
*stateblock
= device
->stateBlock
;
416 BOOL vs
= stateblock
->vertexShader
&& device
->vs_selected_mode
!= SHADER_NONE
;
419 if (device
->up_strided
)
421 /* Note: this is a ddraw fixed-function code path. */
422 TRACE("=============================== Strided Input ================================\n");
423 device_stream_info_from_strided(gl_info
, device
->up_strided
, stream_info
);
424 if (TRACE_ON(d3d
)) device_trace_strided_stream_info(stream_info
);
428 TRACE("============================= Vertex Declaration =============================\n");
429 device_stream_info_from_declaration(device
, vs
, stream_info
, &fixup
);
432 if (vs
&& !stream_info
->position_transformed
)
434 if (((IWineD3DVertexDeclarationImpl
*)stateblock
->vertexDecl
)->half_float_conv_needed
&& !fixup
)
436 TRACE("Using drawStridedSlow with vertex shaders for FLOAT16 conversion.\n");
437 device
->useDrawStridedSlow
= TRUE
;
441 device
->useDrawStridedSlow
= FALSE
;
446 WORD slow_mask
= (1 << WINED3D_FFP_PSIZE
);
447 slow_mask
|= -!gl_info
->supported
[ARB_VERTEX_ARRAY_BGRA
]
448 & ((1 << WINED3D_FFP_DIFFUSE
) | (1 << WINED3D_FFP_SPECULAR
));
450 if ((stream_info
->position_transformed
|| (stream_info
->use_map
& slow_mask
)) && !fixup
)
452 device
->useDrawStridedSlow
= TRUE
;
456 device
->useDrawStridedSlow
= FALSE
;
461 static void device_preload_texture(IWineD3DStateBlockImpl
*stateblock
, unsigned int idx
)
463 IWineD3DBaseTextureImpl
*texture
;
464 enum WINED3DSRGB srgb
;
466 if (!(texture
= (IWineD3DBaseTextureImpl
*)stateblock
->textures
[idx
])) return;
467 srgb
= stateblock
->samplerState
[idx
][WINED3DSAMP_SRGBTEXTURE
] ? SRGB_SRGB
: SRGB_RGB
;
468 texture
->baseTexture
.internal_preload((IWineD3DBaseTexture
*)texture
, srgb
);
471 void device_preload_textures(IWineD3DDeviceImpl
*device
)
473 IWineD3DStateBlockImpl
*stateblock
= device
->stateBlock
;
476 if (use_vs(stateblock
))
478 for (i
= 0; i
< MAX_VERTEX_SAMPLERS
; ++i
)
480 if (((IWineD3DBaseShaderImpl
*)stateblock
->vertexShader
)->baseShader
.reg_maps
.sampler_type
[i
])
481 device_preload_texture(stateblock
, MAX_FRAGMENT_SAMPLERS
+ i
);
485 if (use_ps(stateblock
))
487 for (i
= 0; i
< MAX_FRAGMENT_SAMPLERS
; ++i
)
489 if (((IWineD3DBaseShaderImpl
*)stateblock
->pixelShader
)->baseShader
.reg_maps
.sampler_type
[i
])
490 device_preload_texture(stateblock
, i
);
495 WORD ffu_map
= device
->fixed_function_usage_map
;
497 for (i
= 0; ffu_map
; ffu_map
>>= 1, ++i
)
500 device_preload_texture(stateblock
, i
);
505 BOOL
device_context_add(IWineD3DDeviceImpl
*device
, struct wined3d_context
*context
)
507 struct wined3d_context
**new_array
;
509 TRACE("Adding context %p.\n", context
);
511 if (!device
->contexts
) new_array
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_array
));
512 else new_array
= HeapReAlloc(GetProcessHeap(), 0, device
->contexts
, sizeof(*new_array
) * (device
->numContexts
+ 1));
516 ERR("Failed to grow the context array.\n");
520 new_array
[device
->numContexts
++] = context
;
521 device
->contexts
= new_array
;
525 void device_context_remove(IWineD3DDeviceImpl
*device
, struct wined3d_context
*context
)
527 struct wined3d_context
**new_array
;
531 TRACE("Removing context %p.\n", context
);
533 for (i
= 0; i
< device
->numContexts
; ++i
)
535 if (device
->contexts
[i
] == context
)
544 ERR("Context %p doesn't exist in context array.\n", context
);
548 if (!--device
->numContexts
)
550 HeapFree(GetProcessHeap(), 0, device
->contexts
);
551 device
->contexts
= NULL
;
555 memmove(&device
->contexts
[i
], &device
->contexts
[i
+ 1], (device
->numContexts
- i
) * sizeof(*device
->contexts
));
556 new_array
= HeapReAlloc(GetProcessHeap(), 0, device
->contexts
, device
->numContexts
* sizeof(*device
->contexts
));
559 ERR("Failed to shrink context array. Oh well.\n");
563 device
->contexts
= new_array
;
567 /**********************************************************
568 * IUnknown parts follows
569 **********************************************************/
571 static HRESULT WINAPI
IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice
*iface
,REFIID riid
,LPVOID
*ppobj
)
573 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
575 TRACE("(%p)->(%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
576 if (IsEqualGUID(riid
, &IID_IUnknown
)
577 || IsEqualGUID(riid
, &IID_IWineD3DBase
)
578 || IsEqualGUID(riid
, &IID_IWineD3DDevice
)) {
579 IUnknown_AddRef(iface
);
584 return E_NOINTERFACE
;
587 static ULONG WINAPI
IWineD3DDeviceImpl_AddRef(IWineD3DDevice
*iface
) {
588 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
589 ULONG refCount
= InterlockedIncrement(&This
->ref
);
591 TRACE("(%p) : AddRef increasing from %d\n", This
, refCount
- 1);
595 static ULONG WINAPI
IWineD3DDeviceImpl_Release(IWineD3DDevice
*iface
) {
596 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
597 ULONG refCount
= InterlockedDecrement(&This
->ref
);
599 TRACE("(%p) : Releasing from %d\n", This
, refCount
+ 1);
604 for (i
= 0; i
< sizeof(This
->multistate_funcs
)/sizeof(This
->multistate_funcs
[0]); ++i
) {
605 HeapFree(GetProcessHeap(), 0, This
->multistate_funcs
[i
]);
606 This
->multistate_funcs
[i
] = NULL
;
609 /* TODO: Clean up all the surfaces and textures! */
610 /* NOTE: You must release the parent if the object was created via a callback
611 ** ***************************/
613 if (!list_empty(&This
->resources
))
615 IWineD3DResourceImpl
*resource
;
616 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This
);
618 LIST_FOR_EACH_ENTRY(resource
, &This
->resources
, IWineD3DResourceImpl
, resource
.resource_list_entry
)
620 WINED3DRESOURCETYPE type
= IWineD3DResource_GetType((IWineD3DResource
*)resource
);
621 FIXME("Leftover resource %p with type %s (%#x).\n",
622 resource
, debug_d3dresourcetype(type
), type
);
626 if(This
->contexts
) ERR("Context array not freed!\n");
627 if (This
->hardwareCursor
) DestroyCursor(This
->hardwareCursor
);
628 This
->haveHardwareCursor
= FALSE
;
630 IWineD3D_Release(This
->wined3d
);
631 This
->wined3d
= NULL
;
632 HeapFree(GetProcessHeap(), 0, This
);
633 TRACE("Freed device %p\n", This
);
639 /**********************************************************
640 * IWineD3DDevice implementation follows
641 **********************************************************/
642 static HRESULT WINAPI
IWineD3DDeviceImpl_GetParent(IWineD3DDevice
*iface
, IUnknown
**pParent
) {
643 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
644 *pParent
= This
->parent
;
645 IUnknown_AddRef(This
->parent
);
649 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice
*iface
, struct wined3d_buffer_desc
*desc
,
650 const void *data
, IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
, IWineD3DBuffer
**buffer
)
652 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
653 struct wined3d_buffer
*object
;
656 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface
, desc
, data
, parent
, buffer
);
658 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
661 ERR("Failed to allocate memory\n");
662 return E_OUTOFMEMORY
;
665 FIXME("Ignoring access flags (pool)\n");
667 hr
= buffer_init(object
, This
, desc
->byte_width
, desc
->usage
, WINED3DFMT_UNKNOWN
,
668 WINED3DPOOL_MANAGED
, GL_ARRAY_BUFFER_ARB
, data
, parent
, parent_ops
);
671 WARN("Failed to initialize buffer, hr %#x.\n", hr
);
672 HeapFree(GetProcessHeap(), 0, object
);
675 object
->desc
= *desc
;
677 TRACE("Created buffer %p.\n", object
);
679 *buffer
= (IWineD3DBuffer
*)object
;
684 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice
*iface
,
685 UINT Size
, DWORD Usage
, WINED3DPOOL Pool
, IWineD3DBuffer
**ppVertexBuffer
,
686 IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
)
688 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
689 struct wined3d_buffer
*object
;
692 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
693 iface
, Size
, Usage
, Pool
, ppVertexBuffer
, parent
, parent_ops
);
695 if (Pool
== WINED3DPOOL_SCRATCH
)
697 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
698 * anyway, SCRATCH vertex buffers aren't usable anywhere
700 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
701 *ppVertexBuffer
= NULL
;
702 return WINED3DERR_INVALIDCALL
;
705 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
708 ERR("Out of memory\n");
709 *ppVertexBuffer
= NULL
;
710 return WINED3DERR_OUTOFVIDEOMEMORY
;
713 hr
= buffer_init(object
, This
, Size
, Usage
, WINED3DFMT_VERTEXDATA
,
714 Pool
, GL_ARRAY_BUFFER_ARB
, NULL
, parent
, parent_ops
);
717 WARN("Failed to initialize buffer, hr %#x.\n", hr
);
718 HeapFree(GetProcessHeap(), 0, object
);
722 TRACE("Created buffer %p.\n", object
);
723 *ppVertexBuffer
= (IWineD3DBuffer
*)object
;
728 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice
*iface
,
729 UINT Length
, DWORD Usage
, WINED3DPOOL Pool
, IWineD3DBuffer
**ppIndexBuffer
,
730 IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
)
732 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
733 struct wined3d_buffer
*object
;
736 TRACE("(%p) Creating index buffer\n", This
);
738 /* Allocate the storage for the device */
739 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
742 ERR("Out of memory\n");
743 *ppIndexBuffer
= NULL
;
744 return WINED3DERR_OUTOFVIDEOMEMORY
;
747 hr
= buffer_init(object
, This
, Length
, Usage
| WINED3DUSAGE_STATICDECL
,
748 WINED3DFMT_UNKNOWN
, Pool
, GL_ELEMENT_ARRAY_BUFFER_ARB
, NULL
,
752 WARN("Failed to initialize buffer, hr %#x\n", hr
);
753 HeapFree(GetProcessHeap(), 0, object
);
757 TRACE("Created buffer %p.\n", object
);
759 *ppIndexBuffer
= (IWineD3DBuffer
*) object
;
764 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice
*iface
,
765 WINED3DSTATEBLOCKTYPE type
, IWineD3DStateBlock
**stateblock
, IUnknown
*parent
)
767 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
768 IWineD3DStateBlockImpl
*object
;
771 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
774 ERR("Failed to allocate stateblock memory.\n");
775 return E_OUTOFMEMORY
;
778 hr
= stateblock_init(object
, This
, type
);
781 WARN("Failed to initialize stateblock, hr %#x.\n", hr
);
782 HeapFree(GetProcessHeap(), 0, object
);
786 TRACE("Created stateblock %p.\n", object
);
787 *stateblock
= (IWineD3DStateBlock
*)object
;
792 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice
*iface
, UINT Width
, UINT Height
,
793 WINED3DFORMAT Format
, BOOL Lockable
, BOOL Discard
, UINT Level
, IWineD3DSurface
**ppSurface
,
794 DWORD Usage
, WINED3DPOOL Pool
, WINED3DMULTISAMPLE_TYPE MultiSample
, DWORD MultisampleQuality
,
795 WINED3DSURFTYPE Impl
, IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
)
797 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
798 IWineD3DSurfaceImpl
*object
;
801 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
802 iface
, Width
, Height
, debug_d3dformat(Format
), Format
, Lockable
, Discard
, Level
);
803 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
804 ppSurface
, debug_d3dusage(Usage
), Usage
, debug_d3dpool(Pool
), Pool
, MultiSample
, MultisampleQuality
);
805 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl
, parent
, parent_ops
);
807 if (Impl
== SURFACE_OPENGL
&& !This
->adapter
)
809 ERR("OpenGL surfaces are not available without OpenGL.\n");
810 return WINED3DERR_NOTAVAILABLE
;
813 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
816 ERR("Failed to allocate surface memory.\n");
817 return WINED3DERR_OUTOFVIDEOMEMORY
;
820 hr
= surface_init(object
, Impl
, This
->surface_alignment
, Width
, Height
, Level
, Lockable
,
821 Discard
, MultiSample
, MultisampleQuality
, This
, Usage
, Format
, Pool
, parent
, parent_ops
);
824 WARN("Failed to initialize surface, returning %#x.\n", hr
);
825 HeapFree(GetProcessHeap(), 0, object
);
829 TRACE("(%p) : Created surface %p\n", This
, object
);
831 *ppSurface
= (IWineD3DSurface
*)object
;
836 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice
*iface
,
837 IWineD3DResource
*resource
, IUnknown
*parent
, IWineD3DRendertargetView
**rendertarget_view
)
839 struct wined3d_rendertarget_view
*object
;
841 TRACE("iface %p, resource %p, parent %p, rendertarget_view %p.\n",
842 iface
, resource
, parent
, rendertarget_view
);
844 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
847 ERR("Failed to allocate memory\n");
848 return E_OUTOFMEMORY
;
851 wined3d_rendertarget_view_init(object
, resource
, parent
);
853 TRACE("Created render target view %p.\n", object
);
854 *rendertarget_view
= (IWineD3DRendertargetView
*)object
;
859 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice
*iface
,
860 UINT Width
, UINT Height
, UINT Levels
, DWORD Usage
, WINED3DFORMAT Format
, WINED3DPOOL Pool
,
861 IWineD3DTexture
**ppTexture
, IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
)
863 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
864 IWineD3DTextureImpl
*object
;
867 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This
, Width
, Height
, Levels
, Usage
);
868 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
869 Format
, debug_d3dformat(Format
), Pool
, ppTexture
, parent
);
871 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
874 ERR("Out of memory\n");
876 return WINED3DERR_OUTOFVIDEOMEMORY
;
879 hr
= texture_init(object
, Width
, Height
, Levels
, This
, Usage
, Format
, Pool
, parent
, parent_ops
);
882 WARN("Failed to initialize texture, returning %#x\n", hr
);
883 HeapFree(GetProcessHeap(), 0, object
);
888 *ppTexture
= (IWineD3DTexture
*)object
;
890 TRACE("(%p) : Created texture %p\n", This
, object
);
895 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice
*iface
,
896 UINT Width
, UINT Height
, UINT Depth
, UINT Levels
, DWORD Usage
, WINED3DFORMAT Format
, WINED3DPOOL Pool
,
897 IWineD3DVolumeTexture
**ppVolumeTexture
, IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
)
899 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
900 IWineD3DVolumeTextureImpl
*object
;
903 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
904 Depth
, Levels
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
906 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
909 ERR("Out of memory\n");
910 *ppVolumeTexture
= NULL
;
911 return WINED3DERR_OUTOFVIDEOMEMORY
;
914 hr
= volumetexture_init(object
, Width
, Height
, Depth
, Levels
, This
, Usage
, Format
, Pool
, parent
, parent_ops
);
917 WARN("Failed to initialize volumetexture, returning %#x\n", hr
);
918 HeapFree(GetProcessHeap(), 0, object
);
919 *ppVolumeTexture
= NULL
;
923 TRACE("(%p) : Created volume texture %p.\n", This
, object
);
924 *ppVolumeTexture
= (IWineD3DVolumeTexture
*)object
;
929 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice
*iface
, UINT Width
, UINT Height
,
930 UINT Depth
, DWORD Usage
, WINED3DFORMAT Format
, WINED3DPOOL Pool
, IWineD3DVolume
**ppVolume
,
931 IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
)
933 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
934 IWineD3DVolumeImpl
*object
;
937 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
938 Depth
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
940 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
943 ERR("Out of memory\n");
945 return WINED3DERR_OUTOFVIDEOMEMORY
;
948 hr
= volume_init(object
, This
, Width
, Height
, Depth
, Usage
, Format
, Pool
, parent
, parent_ops
);
951 WARN("Failed to initialize volume, returning %#x.\n", hr
);
952 HeapFree(GetProcessHeap(), 0, object
);
956 TRACE("(%p) : Created volume %p.\n", This
, object
);
957 *ppVolume
= (IWineD3DVolume
*)object
;
962 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice
*iface
, UINT EdgeLength
, UINT Levels
,
963 DWORD Usage
, WINED3DFORMAT Format
, WINED3DPOOL Pool
, IWineD3DCubeTexture
**ppCubeTexture
,
964 IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
)
966 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
967 IWineD3DCubeTextureImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
970 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
973 ERR("Out of memory\n");
974 *ppCubeTexture
= NULL
;
975 return WINED3DERR_OUTOFVIDEOMEMORY
;
978 hr
= cubetexture_init(object
, EdgeLength
, Levels
, This
, Usage
, Format
, Pool
, parent
, parent_ops
);
981 WARN("Failed to initialize cubetexture, returning %#x\n", hr
);
982 HeapFree(GetProcessHeap(), 0, object
);
983 *ppCubeTexture
= NULL
;
987 TRACE("(%p) : Created Cube Texture %p\n", This
, object
);
988 *ppCubeTexture
= (IWineD3DCubeTexture
*)object
;
993 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice
*iface
,
994 WINED3DQUERYTYPE type
, IWineD3DQuery
**query
, IUnknown
*parent
)
996 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
997 IWineD3DQueryImpl
*object
;
1000 TRACE("iface %p, type %#x, query %p, parent %p.\n", iface
, type
, query
, parent
);
1002 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1005 ERR("Failed to allocate query memory.\n");
1006 return E_OUTOFMEMORY
;
1009 hr
= query_init(object
, This
, type
, parent
);
1012 WARN("Failed to initialize query, hr %#x.\n", hr
);
1013 HeapFree(GetProcessHeap(), 0, object
);
1017 TRACE("Created query %p.\n", object
);
1018 *query
= (IWineD3DQuery
*)object
;
1023 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice
*iface
,
1024 WINED3DPRESENT_PARAMETERS
*present_parameters
, IWineD3DSwapChain
**swapchain
,
1025 IUnknown
*parent
, WINED3DSURFTYPE surface_type
)
1027 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1028 IWineD3DSwapChainImpl
*object
;
1031 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1032 iface
, present_parameters
, swapchain
, parent
, surface_type
);
1034 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1037 ERR("Failed to allocate swapchain memory.\n");
1038 return E_OUTOFMEMORY
;
1041 hr
= swapchain_init(object
, surface_type
, This
, present_parameters
, parent
);
1044 WARN("Failed to initialize swapchain, hr %#x.\n", hr
);
1045 HeapFree(GetProcessHeap(), 0, object
);
1049 TRACE("Created swapchain %p.\n", object
);
1050 *swapchain
= (IWineD3DSwapChain
*)object
;
1055 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1056 static UINT WINAPI
IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice
*iface
) {
1057 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1058 TRACE("(%p)\n", This
);
1060 return This
->NumberOfSwapChains
;
1063 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice
*iface
, UINT iSwapChain
, IWineD3DSwapChain
**pSwapChain
) {
1064 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1065 TRACE("(%p) : swapchain %d\n", This
, iSwapChain
);
1067 if(iSwapChain
< This
->NumberOfSwapChains
) {
1068 *pSwapChain
= This
->swapchains
[iSwapChain
];
1069 IWineD3DSwapChain_AddRef(*pSwapChain
);
1070 TRACE("(%p) returning %p\n", This
, *pSwapChain
);
1073 TRACE("Swapchain out of range\n");
1075 return WINED3DERR_INVALIDCALL
;
1079 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice
*iface
,
1080 IWineD3DVertexDeclaration
**declaration
, IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
,
1081 const WINED3DVERTEXELEMENT
*elements
, UINT element_count
)
1083 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1084 IWineD3DVertexDeclarationImpl
*object
= NULL
;
1087 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1088 iface
, declaration
, parent
, elements
, element_count
);
1090 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1093 ERR("Failed to allocate vertex declaration memory.\n");
1094 return E_OUTOFMEMORY
;
1097 hr
= vertexdeclaration_init(object
, This
, elements
, element_count
, parent
, parent_ops
);
1100 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr
);
1101 HeapFree(GetProcessHeap(), 0, object
);
1105 TRACE("Created vertex declaration %p.\n", object
);
1106 *declaration
= (IWineD3DVertexDeclaration
*)object
;
1111 struct wined3d_fvf_convert_state
1113 const struct wined3d_gl_info
*gl_info
;
1114 WINED3DVERTEXELEMENT
*elements
;
1119 static void append_decl_element(struct wined3d_fvf_convert_state
*state
,
1120 WINED3DFORMAT format
, WINED3DDECLUSAGE usage
, UINT usage_idx
)
1122 WINED3DVERTEXELEMENT
*elements
= state
->elements
;
1123 const struct wined3d_format_desc
*format_desc
;
1124 UINT offset
= state
->offset
;
1125 UINT idx
= state
->idx
;
1127 elements
[idx
].format
= format
;
1128 elements
[idx
].input_slot
= 0;
1129 elements
[idx
].offset
= offset
;
1130 elements
[idx
].output_slot
= 0;
1131 elements
[idx
].method
= WINED3DDECLMETHOD_DEFAULT
;
1132 elements
[idx
].usage
= usage
;
1133 elements
[idx
].usage_idx
= usage_idx
;
1135 format_desc
= getFormatDescEntry(format
, state
->gl_info
);
1136 state
->offset
+= format_desc
->component_count
* format_desc
->component_size
;
1140 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl
*This
, /* For the GL info, which has the type table */
1141 DWORD fvf
, WINED3DVERTEXELEMENT
**ppVertexElements
)
1143 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
1144 BOOL has_pos
= (fvf
& WINED3DFVF_POSITION_MASK
) != 0;
1145 BOOL has_blend
= (fvf
& WINED3DFVF_XYZB5
) > WINED3DFVF_XYZRHW
;
1146 BOOL has_blend_idx
= has_blend
&&
1147 (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB5
) ||
1148 (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
) ||
1149 (fvf
& WINED3DFVF_LASTBETA_UBYTE4
));
1150 BOOL has_normal
= (fvf
& WINED3DFVF_NORMAL
) != 0;
1151 BOOL has_psize
= (fvf
& WINED3DFVF_PSIZE
) != 0;
1152 BOOL has_diffuse
= (fvf
& WINED3DFVF_DIFFUSE
) != 0;
1153 BOOL has_specular
= (fvf
& WINED3DFVF_SPECULAR
) !=0;
1155 DWORD num_textures
= (fvf
& WINED3DFVF_TEXCOUNT_MASK
) >> WINED3DFVF_TEXCOUNT_SHIFT
;
1156 DWORD texcoords
= (fvf
& 0xFFFF0000) >> 16;
1157 struct wined3d_fvf_convert_state state
;
1160 DWORD num_blends
= 1 + (((fvf
& WINED3DFVF_XYZB5
) - WINED3DFVF_XYZB1
) >> 1);
1161 if (has_blend_idx
) num_blends
--;
1163 /* Compute declaration size */
1164 size
= has_pos
+ (has_blend
&& num_blends
> 0) + has_blend_idx
+ has_normal
+
1165 has_psize
+ has_diffuse
+ has_specular
+ num_textures
;
1167 state
.gl_info
= gl_info
;
1168 state
.elements
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(*state
.elements
));
1169 if (!state
.elements
) return ~0U;
1175 if (!has_blend
&& (fvf
& WINED3DFVF_XYZRHW
))
1176 append_decl_element(&state
, WINED3DFMT_R32G32B32A32_FLOAT
, WINED3DDECLUSAGE_POSITIONT
, 0);
1177 else if ((fvf
& WINED3DFVF_XYZW
) == WINED3DFVF_XYZW
)
1178 append_decl_element(&state
, WINED3DFMT_R32G32B32A32_FLOAT
, WINED3DDECLUSAGE_POSITION
, 0);
1180 append_decl_element(&state
, WINED3DFMT_R32G32B32_FLOAT
, WINED3DDECLUSAGE_POSITION
, 0);
1183 if (has_blend
&& (num_blends
> 0))
1185 if ((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB2
&& (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
))
1186 append_decl_element(&state
, WINED3DFMT_B8G8R8A8_UNORM
, WINED3DDECLUSAGE_BLENDWEIGHT
, 0);
1192 append_decl_element(&state
, WINED3DFMT_R32_FLOAT
, WINED3DDECLUSAGE_BLENDWEIGHT
, 0);
1195 append_decl_element(&state
, WINED3DFMT_R32G32_FLOAT
, WINED3DDECLUSAGE_BLENDWEIGHT
, 0);
1198 append_decl_element(&state
, WINED3DFMT_R32G32B32_FLOAT
, WINED3DDECLUSAGE_BLENDWEIGHT
, 0);
1201 append_decl_element(&state
, WINED3DFMT_R32G32B32A32_FLOAT
, WINED3DDECLUSAGE_BLENDWEIGHT
, 0);
1204 ERR("Unexpected amount of blend values: %u\n", num_blends
);
1211 if ((fvf
& WINED3DFVF_LASTBETA_UBYTE4
)
1212 || ((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB2
&& (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
)))
1213 append_decl_element(&state
, WINED3DFMT_R8G8B8A8_UINT
, WINED3DDECLUSAGE_BLENDINDICES
, 0);
1214 else if (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
)
1215 append_decl_element(&state
, WINED3DFMT_B8G8R8A8_UNORM
, WINED3DDECLUSAGE_BLENDINDICES
, 0);
1217 append_decl_element(&state
, WINED3DFMT_R32_FLOAT
, WINED3DDECLUSAGE_BLENDINDICES
, 0);
1220 if (has_normal
) append_decl_element(&state
, WINED3DFMT_R32G32B32_FLOAT
, WINED3DDECLUSAGE_NORMAL
, 0);
1221 if (has_psize
) append_decl_element(&state
, WINED3DFMT_R32_FLOAT
, WINED3DDECLUSAGE_PSIZE
, 0);
1222 if (has_diffuse
) append_decl_element(&state
, WINED3DFMT_B8G8R8A8_UNORM
, WINED3DDECLUSAGE_COLOR
, 0);
1223 if (has_specular
) append_decl_element(&state
, WINED3DFMT_B8G8R8A8_UNORM
, WINED3DDECLUSAGE_COLOR
, 1);
1225 for (idx
= 0; idx
< num_textures
; ++idx
)
1227 switch ((texcoords
>> (idx
* 2)) & 0x03)
1229 case WINED3DFVF_TEXTUREFORMAT1
:
1230 append_decl_element(&state
, WINED3DFMT_R32_FLOAT
, WINED3DDECLUSAGE_TEXCOORD
, idx
);
1232 case WINED3DFVF_TEXTUREFORMAT2
:
1233 append_decl_element(&state
, WINED3DFMT_R32G32_FLOAT
, WINED3DDECLUSAGE_TEXCOORD
, idx
);
1235 case WINED3DFVF_TEXTUREFORMAT3
:
1236 append_decl_element(&state
, WINED3DFMT_R32G32B32_FLOAT
, WINED3DDECLUSAGE_TEXCOORD
, idx
);
1238 case WINED3DFVF_TEXTUREFORMAT4
:
1239 append_decl_element(&state
, WINED3DFMT_R32G32B32A32_FLOAT
, WINED3DDECLUSAGE_TEXCOORD
, idx
);
1244 *ppVertexElements
= state
.elements
;
1248 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice
*iface
,
1249 IWineD3DVertexDeclaration
**declaration
, IUnknown
*parent
,
1250 const struct wined3d_parent_ops
*parent_ops
, DWORD fvf
)
1252 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1253 WINED3DVERTEXELEMENT
*elements
;
1257 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface
, declaration
, parent
, fvf
);
1259 size
= ConvertFvfToDeclaration(This
, fvf
, &elements
);
1260 if (size
== ~0U) return E_OUTOFMEMORY
;
1262 hr
= IWineD3DDevice_CreateVertexDeclaration(iface
, declaration
, parent
, parent_ops
, elements
, size
);
1263 HeapFree(GetProcessHeap(), 0, elements
);
1267 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice
*iface
,
1268 const DWORD
*pFunction
, const struct wined3d_shader_signature
*output_signature
,
1269 IWineD3DVertexShader
**ppVertexShader
, IUnknown
*parent
,
1270 const struct wined3d_parent_ops
*parent_ops
)
1272 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1273 IWineD3DVertexShaderImpl
*object
;
1276 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1279 ERR("Failed to allocate shader memory.\n");
1280 return E_OUTOFMEMORY
;
1283 hr
= vertexshader_init(object
, This
, pFunction
, output_signature
, parent
, parent_ops
);
1286 WARN("Failed to initialize vertex shader, hr %#x.\n", hr
);
1287 HeapFree(GetProcessHeap(), 0, object
);
1291 TRACE("Created vertex shader %p.\n", object
);
1292 *ppVertexShader
= (IWineD3DVertexShader
*)object
;
1297 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice
*iface
,
1298 const DWORD
*byte_code
, const struct wined3d_shader_signature
*output_signature
,
1299 IWineD3DGeometryShader
**shader
, IUnknown
*parent
,
1300 const struct wined3d_parent_ops
*parent_ops
)
1302 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1303 struct wined3d_geometryshader
*object
;
1306 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1309 ERR("Failed to allocate shader memory.\n");
1310 return E_OUTOFMEMORY
;
1313 hr
= geometryshader_init(object
, This
, byte_code
, output_signature
, parent
, parent_ops
);
1316 WARN("Failed to initialize geometry shader, hr %#x.\n", hr
);
1317 HeapFree(GetProcessHeap(), 0, object
);
1321 TRACE("Created geometry shader %p.\n", object
);
1322 *shader
= (IWineD3DGeometryShader
*)object
;
1327 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice
*iface
,
1328 const DWORD
*pFunction
, const struct wined3d_shader_signature
*output_signature
,
1329 IWineD3DPixelShader
**ppPixelShader
, IUnknown
*parent
,
1330 const struct wined3d_parent_ops
*parent_ops
)
1332 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1333 IWineD3DPixelShaderImpl
*object
;
1336 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1339 ERR("Failed to allocate shader memory.\n");
1340 return E_OUTOFMEMORY
;
1343 hr
= pixelshader_init(object
, This
, pFunction
, output_signature
, parent
, parent_ops
);
1346 WARN("Failed to initialize pixel shader, hr %#x.\n", hr
);
1347 HeapFree(GetProcessHeap(), 0, object
);
1351 TRACE("Created pixel shader %p.\n", object
);
1352 *ppPixelShader
= (IWineD3DPixelShader
*)object
;
1357 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice
*iface
, DWORD Flags
,
1358 const PALETTEENTRY
*PalEnt
, IWineD3DPalette
**Palette
, IUnknown
*Parent
)
1360 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1361 IWineD3DPaletteImpl
*object
;
1364 TRACE("iface %p, flags %#x, entries %p, palette %p, parent %p.\n",
1365 iface
, Flags
, PalEnt
, Palette
, Parent
);
1367 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1370 ERR("Failed to allocate palette memory.\n");
1371 return E_OUTOFMEMORY
;
1374 hr
= wined3d_palette_init(object
, This
, Flags
, PalEnt
, Parent
);
1377 WARN("Failed to initialize palette, hr %#x.\n", hr
);
1378 HeapFree(GetProcessHeap(), 0, object
);
1382 TRACE("Created palette %p.\n", object
);
1383 *Palette
= (IWineD3DPalette
*)object
;
1388 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl
*This
, const char *filename
) {
1392 HDC dcb
= NULL
, dcs
= NULL
;
1393 WINEDDCOLORKEY colorkey
;
1395 hbm
= LoadImageA(NULL
, filename
, IMAGE_BITMAP
, 0, 0, LR_LOADFROMFILE
| LR_CREATEDIBSECTION
);
1398 GetObjectA(hbm
, sizeof(BITMAP
), &bm
);
1399 dcb
= CreateCompatibleDC(NULL
);
1401 SelectObject(dcb
, hbm
);
1405 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1406 * couldn't be loaded
1408 memset(&bm
, 0, sizeof(bm
));
1413 hr
= IWineD3DDevice_CreateSurface((IWineD3DDevice
*)This
, bm
.bmWidth
, bm
.bmHeight
, WINED3DFMT_B5G6R5_UNORM
, TRUE
,
1414 FALSE
, 0, &This
->logo_surface
, 0, WINED3DPOOL_DEFAULT
, WINED3DMULTISAMPLE_NONE
, 0, SURFACE_OPENGL
,
1415 NULL
, &wined3d_null_parent_ops
);
1417 ERR("Wine logo requested, but failed to create surface\n");
1422 hr
= IWineD3DSurface_GetDC(This
->logo_surface
, &dcs
);
1423 if(FAILED(hr
)) goto out
;
1424 BitBlt(dcs
, 0, 0, bm
.bmWidth
, bm
.bmHeight
, dcb
, 0, 0, SRCCOPY
);
1425 IWineD3DSurface_ReleaseDC(This
->logo_surface
, dcs
);
1427 colorkey
.dwColorSpaceLowValue
= 0;
1428 colorkey
.dwColorSpaceHighValue
= 0;
1429 IWineD3DSurface_SetColorKey(This
->logo_surface
, WINEDDCKEY_SRCBLT
, &colorkey
);
1431 /* Fill the surface with a white color to show that wined3d is there */
1432 IWineD3DDevice_ColorFill((IWineD3DDevice
*) This
, This
->logo_surface
, NULL
, 0xffffffff);
1436 if (dcb
) DeleteDC(dcb
);
1437 if (hbm
) DeleteObject(hbm
);
1440 /* Context activation is done by the caller. */
1441 static void create_dummy_textures(IWineD3DDeviceImpl
*This
)
1443 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
1445 /* Under DirectX you can have texture stage operations even if no texture is
1446 bound, whereas opengl will only do texture operations when a valid texture is
1447 bound. We emulate this by creating dummy textures and binding them to each
1448 texture stage, but disable all stages by default. Hence if a stage is enabled
1449 then the default texture will kick in until replaced by a SetTexture call */
1452 if (gl_info
->supported
[APPLE_CLIENT_STORAGE
])
1454 /* The dummy texture does not have client storage backing */
1455 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
1456 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1459 for (i
= 0; i
< gl_info
->limits
.textures
; ++i
)
1461 GLubyte white
= 255;
1463 /* Make appropriate texture active */
1464 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
+ i
));
1465 checkGLcall("glActiveTextureARB");
1467 /* Generate an opengl texture name */
1468 glGenTextures(1, &This
->dummyTextureName
[i
]);
1469 checkGLcall("glGenTextures");
1470 TRACE("Dummy Texture %d given name %d\n", i
, This
->dummyTextureName
[i
]);
1472 /* Generate a dummy 2d texture (not using 1d because they cause many
1473 * DRI drivers fall back to sw) */
1474 glBindTexture(GL_TEXTURE_2D
, This
->dummyTextureName
[i
]);
1475 checkGLcall("glBindTexture");
1477 glTexImage2D(GL_TEXTURE_2D
, 0, GL_LUMINANCE
, 1, 1, 0, GL_LUMINANCE
, GL_UNSIGNED_BYTE
, &white
);
1478 checkGLcall("glTexImage2D");
1481 if (gl_info
->supported
[APPLE_CLIENT_STORAGE
])
1483 /* Reenable because if supported it is enabled by default */
1484 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
1485 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1491 /* Context activation is done by the caller. */
1492 static void destroy_dummy_textures(IWineD3DDeviceImpl
*device
, const struct wined3d_gl_info
*gl_info
)
1495 glDeleteTextures(gl_info
->limits
.textures
, device
->dummyTextureName
);
1496 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1499 memset(device
->dummyTextureName
, 0, gl_info
->limits
.textures
* sizeof(*device
->dummyTextureName
));
1502 static HRESULT WINAPI
IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice
*iface
, HWND window
)
1504 IWineD3DDeviceImpl
*device
= (IWineD3DDeviceImpl
*)iface
;
1506 if (!wined3d_register_window(window
, device
))
1508 ERR("Failed to register window %p.\n", window
);
1512 device
->focus_window
= window
;
1513 SetForegroundWindow(window
);
1518 static void WINAPI
IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice
*iface
)
1520 IWineD3DDeviceImpl
*device
= (IWineD3DDeviceImpl
*)iface
;
1522 if (device
->focus_window
) wined3d_unregister_window(device
->focus_window
);
1523 device
->focus_window
= NULL
;
1526 static HRESULT WINAPI
IWineD3DDeviceImpl_Init3D(IWineD3DDevice
*iface
,
1527 WINED3DPRESENT_PARAMETERS
*pPresentationParameters
)
1529 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1530 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
1531 IWineD3DSwapChainImpl
*swapchain
= NULL
;
1532 struct wined3d_context
*context
;
1537 TRACE("(%p)->(%p)\n", This
, pPresentationParameters
);
1539 if(This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
1540 if(!This
->adapter
->opengl
) return WINED3DERR_INVALIDCALL
;
1542 TRACE("(%p) : Creating stateblock\n", This
);
1543 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1544 hr
= IWineD3DDevice_CreateStateBlock(iface
,
1546 (IWineD3DStateBlock
**)&This
->stateBlock
,
1548 if (WINED3D_OK
!= hr
) { /* Note: No parent needed for initial internal stateblock */
1549 WARN("Failed to create stateblock\n");
1552 TRACE("(%p) : Created stateblock (%p)\n", This
, This
->stateBlock
);
1553 This
->updateStateBlock
= This
->stateBlock
;
1554 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
1556 This
->render_targets
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
1557 sizeof(IWineD3DSurface
*) * gl_info
->limits
.buffers
);
1558 This
->draw_buffers
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
1559 sizeof(GLenum
) * gl_info
->limits
.buffers
);
1561 This
->NumberOfPalettes
= 1;
1562 This
->palettes
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(PALETTEENTRY
*));
1563 if(!This
->palettes
|| !This
->render_targets
|| !This
->draw_buffers
) {
1564 ERR("Out of memory!\n");
1568 This
->palettes
[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY
) * 256);
1569 if(!This
->palettes
[0]) {
1570 ERR("Out of memory!\n");
1574 for (i
= 0; i
< 256; ++i
) {
1575 This
->palettes
[0][i
].peRed
= 0xFF;
1576 This
->palettes
[0][i
].peGreen
= 0xFF;
1577 This
->palettes
[0][i
].peBlue
= 0xFF;
1578 This
->palettes
[0][i
].peFlags
= 0xFF;
1580 This
->currentPalette
= 0;
1582 /* Initialize the texture unit mapping to a 1:1 mapping */
1583 for (state
= 0; state
< MAX_COMBINED_SAMPLERS
; ++state
)
1585 if (state
< gl_info
->limits
.fragment_samplers
)
1587 This
->texUnitMap
[state
] = state
;
1588 This
->rev_tex_unit_map
[state
] = state
;
1590 This
->texUnitMap
[state
] = WINED3D_UNMAPPED_STAGE
;
1591 This
->rev_tex_unit_map
[state
] = WINED3D_UNMAPPED_STAGE
;
1595 /* Setup the implicit swapchain. This also initializes a context. */
1596 TRACE("Creating implicit swapchain\n");
1597 hr
= IWineD3DDeviceParent_CreateSwapChain(This
->device_parent
,
1598 pPresentationParameters
, (IWineD3DSwapChain
**)&swapchain
);
1601 WARN("Failed to create implicit swapchain\n");
1605 This
->NumberOfSwapChains
= 1;
1606 This
->swapchains
= HeapAlloc(GetProcessHeap(), 0, This
->NumberOfSwapChains
* sizeof(IWineD3DSwapChain
*));
1607 if(!This
->swapchains
) {
1608 ERR("Out of memory!\n");
1611 This
->swapchains
[0] = (IWineD3DSwapChain
*) swapchain
;
1613 if(swapchain
->backBuffer
&& swapchain
->backBuffer
[0]) {
1614 TRACE("Setting rendertarget to %p\n", swapchain
->backBuffer
);
1615 This
->render_targets
[0] = swapchain
->backBuffer
[0];
1618 TRACE("Setting rendertarget to %p\n", swapchain
->frontBuffer
);
1619 This
->render_targets
[0] = swapchain
->frontBuffer
;
1621 IWineD3DSurface_AddRef(This
->render_targets
[0]);
1623 /* Depth Stencil support */
1624 This
->stencilBufferTarget
= This
->auto_depth_stencil_buffer
;
1625 if (NULL
!= This
->stencilBufferTarget
) {
1626 IWineD3DSurface_AddRef(This
->stencilBufferTarget
);
1629 hr
= This
->shader_backend
->shader_alloc_private(iface
);
1631 TRACE("Shader private data couldn't be allocated\n");
1634 hr
= This
->frag_pipe
->alloc_private(iface
);
1636 TRACE("Fragment pipeline private data couldn't be allocated\n");
1639 hr
= This
->blitter
->alloc_private(iface
);
1641 TRACE("Blitter private data couldn't be allocated\n");
1645 /* Set up some starting GL setup */
1647 /* Setup all the devices defaults */
1648 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock
*)This
->stateBlock
);
1650 context
= context_acquire(This
, swapchain
->frontBuffer
, CTXUSAGE_RESOURCELOAD
);
1652 create_dummy_textures(This
);
1656 /* Initialize the current view state */
1657 This
->view_ident
= 1;
1658 This
->contexts
[0]->last_was_rhw
= 0;
1659 glGetIntegerv(GL_MAX_LIGHTS
, &This
->maxConcurrentLights
);
1660 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1662 switch(wined3d_settings
.offscreen_rendering_mode
) {
1664 This
->offscreenBuffer
= GL_COLOR_ATTACHMENT0
;
1667 case ORM_BACKBUFFER
:
1669 if (context_get_current()->aux_buffers
> 0)
1671 TRACE("Using auxilliary buffer for offscreen rendering\n");
1672 This
->offscreenBuffer
= GL_AUX0
;
1674 TRACE("Using back buffer for offscreen rendering\n");
1675 This
->offscreenBuffer
= GL_BACK
;
1680 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This
, This
);
1683 context_release(context
);
1685 /* Clear the screen */
1686 IWineD3DDevice_Clear((IWineD3DDevice
*) This
, 0, NULL
,
1687 WINED3DCLEAR_TARGET
| pPresentationParameters
->EnableAutoDepthStencil
? WINED3DCLEAR_ZBUFFER
| WINED3DCLEAR_STENCIL
: 0,
1690 This
->d3d_initialized
= TRUE
;
1692 if(wined3d_settings
.logo
) {
1693 IWineD3DDeviceImpl_LoadLogo(This
, wined3d_settings
.logo
);
1695 This
->highest_dirty_ps_const
= 0;
1696 This
->highest_dirty_vs_const
= 0;
1700 HeapFree(GetProcessHeap(), 0, This
->render_targets
);
1701 HeapFree(GetProcessHeap(), 0, This
->draw_buffers
);
1702 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
1703 This
->NumberOfSwapChains
= 0;
1704 if(This
->palettes
) {
1705 HeapFree(GetProcessHeap(), 0, This
->palettes
[0]);
1706 HeapFree(GetProcessHeap(), 0, This
->palettes
);
1708 This
->NumberOfPalettes
= 0;
1710 IWineD3DSwapChain_Release( (IWineD3DSwapChain
*) swapchain
);
1712 if(This
->stateBlock
) {
1713 IWineD3DStateBlock_Release((IWineD3DStateBlock
*) This
->stateBlock
);
1714 This
->stateBlock
= NULL
;
1716 if (This
->blit_priv
) {
1717 This
->blitter
->free_private(iface
);
1719 if (This
->fragment_priv
) {
1720 This
->frag_pipe
->free_private(iface
);
1722 if (This
->shader_priv
) {
1723 This
->shader_backend
->shader_free_private(iface
);
1728 static HRESULT WINAPI
IWineD3DDeviceImpl_InitGDI(IWineD3DDevice
*iface
,
1729 WINED3DPRESENT_PARAMETERS
*pPresentationParameters
)
1731 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1732 IWineD3DSwapChainImpl
*swapchain
= NULL
;
1735 /* Setup the implicit swapchain */
1736 TRACE("Creating implicit swapchain\n");
1737 hr
= IWineD3DDeviceParent_CreateSwapChain(This
->device_parent
,
1738 pPresentationParameters
, (IWineD3DSwapChain
**)&swapchain
);
1741 WARN("Failed to create implicit swapchain\n");
1745 This
->NumberOfSwapChains
= 1;
1746 This
->swapchains
= HeapAlloc(GetProcessHeap(), 0, This
->NumberOfSwapChains
* sizeof(IWineD3DSwapChain
*));
1747 if(!This
->swapchains
) {
1748 ERR("Out of memory!\n");
1751 This
->swapchains
[0] = (IWineD3DSwapChain
*) swapchain
;
1755 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
1759 static HRESULT WINAPI
device_unload_resource(IWineD3DResource
*resource
, void *ctx
)
1761 IWineD3DResource_UnLoad(resource
);
1762 IWineD3DResource_Release(resource
);
1766 static HRESULT WINAPI
IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice
*iface
,
1767 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain
)
1769 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1770 const struct wined3d_gl_info
*gl_info
;
1771 struct wined3d_context
*context
;
1774 TRACE("(%p)\n", This
);
1776 if(!This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
1778 /* I don't think that the interface guarantees that the device is destroyed from the same thread
1779 * it was created. Thus make sure a context is active for the glDelete* calls
1781 context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
1782 gl_info
= context
->gl_info
;
1784 if(This
->logo_surface
) IWineD3DSurface_Release(This
->logo_surface
);
1786 /* Unload resources */
1787 IWineD3DDevice_EnumResources(iface
, device_unload_resource
, NULL
);
1789 TRACE("Deleting high order patches\n");
1790 for(i
= 0; i
< PATCHMAP_SIZE
; i
++) {
1791 struct list
*e1
, *e2
;
1792 struct WineD3DRectPatch
*patch
;
1793 LIST_FOR_EACH_SAFE(e1
, e2
, &This
->patches
[i
]) {
1794 patch
= LIST_ENTRY(e1
, struct WineD3DRectPatch
, entry
);
1795 IWineD3DDevice_DeletePatch(iface
, patch
->Handle
);
1799 /* Delete the mouse cursor texture */
1800 if(This
->cursorTexture
) {
1802 glDeleteTextures(1, &This
->cursorTexture
);
1804 This
->cursorTexture
= 0;
1807 for (sampler
= 0; sampler
< MAX_FRAGMENT_SAMPLERS
; ++sampler
) {
1808 IWineD3DDevice_SetTexture(iface
, sampler
, NULL
);
1810 for (sampler
= 0; sampler
< MAX_VERTEX_SAMPLERS
; ++sampler
) {
1811 IWineD3DDevice_SetTexture(iface
, WINED3DVERTEXTEXTURESAMPLER0
+ sampler
, NULL
);
1814 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
1815 * private data, it might contain opengl pointers
1817 if(This
->depth_blt_texture
) {
1819 glDeleteTextures(1, &This
->depth_blt_texture
);
1821 This
->depth_blt_texture
= 0;
1823 if (This
->depth_blt_rb
) {
1825 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &This
->depth_blt_rb
);
1827 This
->depth_blt_rb
= 0;
1828 This
->depth_blt_rb_w
= 0;
1829 This
->depth_blt_rb_h
= 0;
1832 /* Release the update stateblock */
1833 if(IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
) > 0){
1834 if(This
->updateStateBlock
!= This
->stateBlock
)
1835 FIXME("(%p) Something's still holding the Update stateblock\n",This
);
1837 This
->updateStateBlock
= NULL
;
1839 { /* because were not doing proper internal refcounts releasing the primary state block
1840 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1841 to set this->stateBlock = NULL; first */
1842 IWineD3DStateBlock
*stateBlock
= (IWineD3DStateBlock
*)This
->stateBlock
;
1843 This
->stateBlock
= NULL
;
1845 /* Release the stateblock */
1846 if(IWineD3DStateBlock_Release(stateBlock
) > 0){
1847 FIXME("(%p) Something's still holding the Update stateblock\n",This
);
1851 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
1852 This
->blitter
->free_private(iface
);
1853 This
->frag_pipe
->free_private(iface
);
1854 This
->shader_backend
->shader_free_private(iface
);
1856 /* Release the buffers (with sanity checks)*/
1857 TRACE("Releasing the depth stencil buffer at %p\n", This
->stencilBufferTarget
);
1858 if(This
->stencilBufferTarget
!= NULL
&& (IWineD3DSurface_Release(This
->stencilBufferTarget
) >0)){
1859 if(This
->auto_depth_stencil_buffer
!= This
->stencilBufferTarget
)
1860 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This
);
1862 This
->stencilBufferTarget
= NULL
;
1864 TRACE("Releasing the render target at %p\n", This
->render_targets
[0]);
1865 if(IWineD3DSurface_Release(This
->render_targets
[0]) >0){
1866 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1868 TRACE("Setting rendertarget to NULL\n");
1869 This
->render_targets
[0] = NULL
;
1871 if (This
->auto_depth_stencil_buffer
) {
1872 if (IWineD3DSurface_Release(This
->auto_depth_stencil_buffer
) > 0)
1874 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This
);
1876 This
->auto_depth_stencil_buffer
= NULL
;
1879 context_release(context
);
1881 for(i
=0; i
< This
->NumberOfSwapChains
; i
++) {
1882 TRACE("Releasing the implicit swapchain %d\n", i
);
1883 if (D3DCB_DestroySwapChain(This
->swapchains
[i
]) > 0) {
1884 FIXME("(%p) Something's still holding the implicit swapchain\n", This
);
1888 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
1889 This
->swapchains
= NULL
;
1890 This
->NumberOfSwapChains
= 0;
1892 for (i
= 0; i
< This
->NumberOfPalettes
; i
++) HeapFree(GetProcessHeap(), 0, This
->palettes
[i
]);
1893 HeapFree(GetProcessHeap(), 0, This
->palettes
);
1894 This
->palettes
= NULL
;
1895 This
->NumberOfPalettes
= 0;
1897 HeapFree(GetProcessHeap(), 0, This
->render_targets
);
1898 HeapFree(GetProcessHeap(), 0, This
->draw_buffers
);
1899 This
->render_targets
= NULL
;
1900 This
->draw_buffers
= NULL
;
1902 This
->d3d_initialized
= FALSE
;
1907 static HRESULT WINAPI
IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice
*iface
, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain
) {
1908 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1911 for(i
=0; i
< This
->NumberOfSwapChains
; i
++) {
1912 TRACE("Releasing the implicit swapchain %d\n", i
);
1913 if (D3DCB_DestroySwapChain(This
->swapchains
[i
]) > 0) {
1914 FIXME("(%p) Something's still holding the implicit swapchain\n", This
);
1918 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
1919 This
->swapchains
= NULL
;
1920 This
->NumberOfSwapChains
= 0;
1924 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
1925 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
1926 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
1928 * There is no way to deactivate thread safety once it is enabled.
1930 static void WINAPI
IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice
*iface
) {
1931 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1933 /*For now just store the flag(needed in case of ddraw) */
1934 This
->createParms
.BehaviorFlags
|= WINED3DCREATE_MULTITHREADED
;
1937 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
,
1938 const WINED3DDISPLAYMODE
* pMode
) {
1940 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1941 const struct wined3d_format_desc
*format_desc
= getFormatDescEntry(pMode
->Format
, &This
->adapter
->gl_info
);
1945 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This
, iSwapChain
, pMode
, pMode
->Width
, pMode
->Height
, pMode
->RefreshRate
, debug_d3dformat(pMode
->Format
));
1947 /* Resize the screen even without a window:
1948 * The app could have unset it with SetCooperativeLevel, but not called
1949 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1950 * but we don't have any hwnd
1953 memset(&devmode
, 0, sizeof(devmode
));
1954 devmode
.dmSize
= sizeof(devmode
);
1955 devmode
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
1956 devmode
.dmBitsPerPel
= format_desc
->byte_count
* 8;
1957 devmode
.dmPelsWidth
= pMode
->Width
;
1958 devmode
.dmPelsHeight
= pMode
->Height
;
1960 devmode
.dmDisplayFrequency
= pMode
->RefreshRate
;
1961 if (pMode
->RefreshRate
!= 0) {
1962 devmode
.dmFields
|= DM_DISPLAYFREQUENCY
;
1965 /* Only change the mode if necessary */
1966 if( (This
->ddraw_width
== pMode
->Width
) &&
1967 (This
->ddraw_height
== pMode
->Height
) &&
1968 (This
->ddraw_format
== pMode
->Format
) &&
1969 (pMode
->RefreshRate
== 0) ) {
1973 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
);
1974 if (ret
!= DISP_CHANGE_SUCCESSFUL
) {
1975 if(devmode
.dmDisplayFrequency
!= 0) {
1976 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1977 devmode
.dmFields
&= ~DM_DISPLAYFREQUENCY
;
1978 devmode
.dmDisplayFrequency
= 0;
1979 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
) != DISP_CHANGE_SUCCESSFUL
;
1981 if(ret
!= DISP_CHANGE_SUCCESSFUL
) {
1982 return WINED3DERR_NOTAVAILABLE
;
1986 /* Store the new values */
1987 This
->ddraw_width
= pMode
->Width
;
1988 This
->ddraw_height
= pMode
->Height
;
1989 This
->ddraw_format
= pMode
->Format
;
1991 /* And finally clip mouse to our screen */
1992 SetRect(&clip_rc
, 0, 0, pMode
->Width
, pMode
->Height
);
1993 ClipCursor(&clip_rc
);
1998 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice
*iface
, IWineD3D
**ppD3D
) {
1999 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2000 *ppD3D
= This
->wined3d
;
2001 TRACE("Returning %p.\n", *ppD3D
);
2002 IWineD3D_AddRef(*ppD3D
);
2006 static UINT WINAPI
IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice
*iface
) {
2007 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2009 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This
,
2010 (This
->adapter
->TextureRam
/(1024*1024)),
2011 ((This
->adapter
->TextureRam
- This
->adapter
->UsedTextureRam
) / (1024*1024)));
2012 /* return simulated texture memory left */
2013 return (This
->adapter
->TextureRam
- This
->adapter
->UsedTextureRam
);
2017 * Get / Set Stream Source
2019 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice
*iface
, UINT StreamNumber
,
2020 IWineD3DBuffer
*pStreamData
, UINT OffsetInBytes
, UINT Stride
)
2022 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2023 IWineD3DBuffer
*oldSrc
;
2025 if (StreamNumber
>= MAX_STREAMS
) {
2026 WARN("Stream out of range %d\n", StreamNumber
);
2027 return WINED3DERR_INVALIDCALL
;
2028 } else if(OffsetInBytes
& 0x3) {
2029 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes
);
2030 return WINED3DERR_INVALIDCALL
;
2033 oldSrc
= This
->updateStateBlock
->streamSource
[StreamNumber
];
2034 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This
, StreamNumber
, oldSrc
, pStreamData
, OffsetInBytes
, Stride
);
2036 This
->updateStateBlock
->changed
.streamSource
|= 1 << StreamNumber
;
2038 if(oldSrc
== pStreamData
&&
2039 This
->updateStateBlock
->streamStride
[StreamNumber
] == Stride
&&
2040 This
->updateStateBlock
->streamOffset
[StreamNumber
] == OffsetInBytes
) {
2041 TRACE("Application is setting the old values over, nothing to do\n");
2045 This
->updateStateBlock
->streamSource
[StreamNumber
] = pStreamData
;
2047 This
->updateStateBlock
->streamStride
[StreamNumber
] = Stride
;
2048 This
->updateStateBlock
->streamOffset
[StreamNumber
] = OffsetInBytes
;
2051 /* Handle recording of state blocks */
2052 if (This
->isRecordingState
) {
2053 TRACE("Recording... not performing anything\n");
2054 if (pStreamData
) IWineD3DBuffer_AddRef(pStreamData
);
2055 if (oldSrc
) IWineD3DBuffer_Release(oldSrc
);
2059 if (pStreamData
!= NULL
) {
2060 InterlockedIncrement(&((struct wined3d_buffer
*)pStreamData
)->bind_count
);
2061 IWineD3DBuffer_AddRef(pStreamData
);
2063 if (oldSrc
!= NULL
) {
2064 InterlockedDecrement(&((struct wined3d_buffer
*)oldSrc
)->bind_count
);
2065 IWineD3DBuffer_Release(oldSrc
);
2068 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2073 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice
*iface
,
2074 UINT StreamNumber
, IWineD3DBuffer
**pStream
, UINT
*pOffset
, UINT
*pStride
)
2076 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2078 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This
, StreamNumber
,
2079 This
->stateBlock
->streamSource
[StreamNumber
],
2080 This
->stateBlock
->streamOffset
[StreamNumber
],
2081 This
->stateBlock
->streamStride
[StreamNumber
]);
2083 if (StreamNumber
>= MAX_STREAMS
) {
2084 WARN("Stream out of range %d\n", StreamNumber
);
2085 return WINED3DERR_INVALIDCALL
;
2087 *pStream
= This
->stateBlock
->streamSource
[StreamNumber
];
2088 *pStride
= This
->stateBlock
->streamStride
[StreamNumber
];
2090 *pOffset
= This
->stateBlock
->streamOffset
[StreamNumber
];
2093 if (*pStream
!= NULL
) {
2094 IWineD3DBuffer_AddRef(*pStream
); /* We have created a new reference to the VB */
2099 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT Divider
) {
2100 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2101 UINT oldFlags
= This
->updateStateBlock
->streamFlags
[StreamNumber
];
2102 UINT oldFreq
= This
->updateStateBlock
->streamFreq
[StreamNumber
];
2104 /* Verify input at least in d3d9 this is invalid*/
2105 if( (Divider
& WINED3DSTREAMSOURCE_INSTANCEDATA
) && (Divider
& WINED3DSTREAMSOURCE_INDEXEDDATA
)){
2106 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2107 return WINED3DERR_INVALIDCALL
;
2109 if( (Divider
& WINED3DSTREAMSOURCE_INSTANCEDATA
) && StreamNumber
== 0 ){
2110 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2111 return WINED3DERR_INVALIDCALL
;
2114 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2115 return WINED3DERR_INVALIDCALL
;
2118 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This
, StreamNumber
, Divider
);
2119 This
->updateStateBlock
->streamFlags
[StreamNumber
] = Divider
& (WINED3DSTREAMSOURCE_INSTANCEDATA
| WINED3DSTREAMSOURCE_INDEXEDDATA
);
2121 This
->updateStateBlock
->changed
.streamFreq
|= 1 << StreamNumber
;
2122 This
->updateStateBlock
->streamFreq
[StreamNumber
] = Divider
& 0x7FFFFF;
2124 if(This
->updateStateBlock
->streamFreq
[StreamNumber
] != oldFreq
||
2125 This
->updateStateBlock
->streamFlags
[StreamNumber
] != oldFlags
) {
2126 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2132 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT
* Divider
) {
2133 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2135 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This
, StreamNumber
, Divider
);
2136 *Divider
= This
->updateStateBlock
->streamFreq
[StreamNumber
] | This
->updateStateBlock
->streamFlags
[StreamNumber
];
2138 TRACE("(%p) : returning %d\n", This
, *Divider
);
2144 * Get / Set & Multiply Transform
2146 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE d3dts
, CONST WINED3DMATRIX
* lpmatrix
) {
2147 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2149 /* Most of this routine, comments included copied from ddraw tree initially: */
2150 TRACE("(%p) : Transform State=%s\n", This
, debug_d3dtstype(d3dts
));
2152 /* Handle recording of state blocks */
2153 if (This
->isRecordingState
) {
2154 TRACE("Recording... not performing anything\n");
2155 This
->updateStateBlock
->changed
.transform
[d3dts
>> 5] |= 1 << (d3dts
& 0x1f);
2156 This
->updateStateBlock
->transforms
[d3dts
] = *lpmatrix
;
2161 * If the new matrix is the same as the current one,
2162 * we cut off any further processing. this seems to be a reasonable
2163 * optimization because as was noticed, some apps (warcraft3 for example)
2164 * tend towards setting the same matrix repeatedly for some reason.
2166 * From here on we assume that the new matrix is different, wherever it matters.
2168 if (!memcmp(&This
->stateBlock
->transforms
[d3dts
].u
.m
[0][0], lpmatrix
, sizeof(WINED3DMATRIX
))) {
2169 TRACE("The app is setting the same matrix over again\n");
2172 conv_mat(lpmatrix
, &This
->stateBlock
->transforms
[d3dts
].u
.m
[0][0]);
2176 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2177 where ViewMat = Camera space, WorldMat = world space.
2179 In OpenGL, camera and world space is combined into GL_MODELVIEW
2180 matrix. The Projection matrix stay projection matrix.
2183 /* Capture the times we can just ignore the change for now */
2184 if (d3dts
== WINED3DTS_VIEW
) { /* handle the VIEW matrix */
2185 This
->view_ident
= !memcmp(lpmatrix
, identity
, 16 * sizeof(float));
2186 /* Handled by the state manager */
2189 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TRANSFORM(d3dts
));
2193 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, WINED3DMATRIX
* pMatrix
) {
2194 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2195 TRACE("(%p) : for Transform State %s\n", This
, debug_d3dtstype(State
));
2196 *pMatrix
= This
->stateBlock
->transforms
[State
];
2200 static HRESULT WINAPI
IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, CONST WINED3DMATRIX
* pMatrix
) {
2201 const WINED3DMATRIX
*mat
= NULL
;
2204 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2205 * below means it will be recorded in a state block change, but it
2206 * works regardless where it is recorded.
2207 * If this is found to be wrong, change to StateBlock.
2209 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2210 TRACE("(%p) : For state %s\n", This
, debug_d3dtstype(State
));
2212 if (State
<= HIGHEST_TRANSFORMSTATE
)
2214 mat
= &This
->updateStateBlock
->transforms
[State
];
2216 FIXME("Unhandled transform state!!\n");
2219 multiply_matrix(&temp
, mat
, pMatrix
);
2221 /* Apply change via set transform - will reapply to eg. lights this way */
2222 return IWineD3DDeviceImpl_SetTransform(iface
, State
, &temp
);
2228 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2229 you can reference any indexes you want as long as that number max are enabled at any
2230 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2231 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2232 but when recording, just build a chain pretty much of commands to be replayed. */
2234 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLight(IWineD3DDevice
*iface
, DWORD Index
, CONST WINED3DLIGHT
* pLight
) {
2236 struct wined3d_light_info
*object
= NULL
;
2237 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2240 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2241 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This
, Index
, pLight
, Hi
);
2243 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2247 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2248 return WINED3DERR_INVALIDCALL
;
2251 switch(pLight
->Type
) {
2252 case WINED3DLIGHT_POINT
:
2253 case WINED3DLIGHT_SPOT
:
2254 case WINED3DLIGHT_PARALLELPOINT
:
2255 case WINED3DLIGHT_GLSPOT
:
2256 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2259 if (pLight
->Attenuation0
< 0.0f
|| pLight
->Attenuation1
< 0.0f
|| pLight
->Attenuation2
< 0.0f
)
2261 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2262 return WINED3DERR_INVALIDCALL
;
2266 case WINED3DLIGHT_DIRECTIONAL
:
2267 /* Ignores attenuation */
2271 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2272 return WINED3DERR_INVALIDCALL
;
2275 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
])
2277 object
= LIST_ENTRY(e
, struct wined3d_light_info
, entry
);
2278 if(object
->OriginalIndex
== Index
) break;
2283 TRACE("Adding new light\n");
2284 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
2286 ERR("Out of memory error when allocating a light\n");
2287 return E_OUTOFMEMORY
;
2289 list_add_head(&This
->updateStateBlock
->lightMap
[Hi
], &object
->entry
);
2290 object
->glIndex
= -1;
2291 object
->OriginalIndex
= Index
;
2294 /* Initialize the object */
2295 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
,
2296 pLight
->Diffuse
.r
, pLight
->Diffuse
.g
, pLight
->Diffuse
.b
, pLight
->Diffuse
.a
,
2297 pLight
->Specular
.r
, pLight
->Specular
.g
, pLight
->Specular
.b
, pLight
->Specular
.a
,
2298 pLight
->Ambient
.r
, pLight
->Ambient
.g
, pLight
->Ambient
.b
, pLight
->Ambient
.a
);
2299 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight
->Position
.x
, pLight
->Position
.y
, pLight
->Position
.z
,
2300 pLight
->Direction
.x
, pLight
->Direction
.y
, pLight
->Direction
.z
);
2301 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight
->Range
, pLight
->Falloff
, pLight
->Theta
, pLight
->Phi
);
2303 /* Save away the information */
2304 object
->OriginalParms
= *pLight
;
2306 switch (pLight
->Type
) {
2307 case WINED3DLIGHT_POINT
:
2309 object
->lightPosn
[0] = pLight
->Position
.x
;
2310 object
->lightPosn
[1] = pLight
->Position
.y
;
2311 object
->lightPosn
[2] = pLight
->Position
.z
;
2312 object
->lightPosn
[3] = 1.0f
;
2313 object
->cutoff
= 180.0f
;
2317 case WINED3DLIGHT_DIRECTIONAL
:
2319 object
->lightPosn
[0] = -pLight
->Direction
.x
;
2320 object
->lightPosn
[1] = -pLight
->Direction
.y
;
2321 object
->lightPosn
[2] = -pLight
->Direction
.z
;
2322 object
->lightPosn
[3] = 0.0f
;
2323 object
->exponent
= 0.0f
;
2324 object
->cutoff
= 180.0f
;
2327 case WINED3DLIGHT_SPOT
:
2329 object
->lightPosn
[0] = pLight
->Position
.x
;
2330 object
->lightPosn
[1] = pLight
->Position
.y
;
2331 object
->lightPosn
[2] = pLight
->Position
.z
;
2332 object
->lightPosn
[3] = 1.0f
;
2335 object
->lightDirn
[0] = pLight
->Direction
.x
;
2336 object
->lightDirn
[1] = pLight
->Direction
.y
;
2337 object
->lightDirn
[2] = pLight
->Direction
.z
;
2338 object
->lightDirn
[3] = 1.0f
;
2341 * opengl-ish and d3d-ish spot lights use too different models for the
2342 * light "intensity" as a function of the angle towards the main light direction,
2343 * so we only can approximate very roughly.
2344 * however spot lights are rather rarely used in games (if ever used at all).
2345 * furthermore if still used, probably nobody pays attention to such details.
2347 if (pLight
->Falloff
== 0) {
2348 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2349 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2350 * will always be 1.0 for both of them, and we don't have to care for the
2351 * rest of the rather complex calculation
2353 object
->exponent
= 0.0f
;
2355 rho
= pLight
->Theta
+ (pLight
->Phi
- pLight
->Theta
)/(2*pLight
->Falloff
);
2356 if (rho
< 0.0001f
) rho
= 0.0001f
;
2357 object
->exponent
= -0.3f
/logf(cosf(rho
/2));
2359 if (object
->exponent
> 128.0f
)
2361 object
->exponent
= 128.0f
;
2363 object
->cutoff
= pLight
->Phi
*90/M_PI
;
2369 FIXME("Unrecognized light type %d\n", pLight
->Type
);
2372 /* Update the live definitions if the light is currently assigned a glIndex */
2373 if (object
->glIndex
!= -1 && !This
->isRecordingState
) {
2374 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(object
->glIndex
));
2379 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLight(IWineD3DDevice
*iface
, DWORD Index
, WINED3DLIGHT
*pLight
)
2381 struct wined3d_light_info
*lightInfo
= NULL
;
2382 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2383 DWORD Hi
= LIGHTMAP_HASHFUNC(Index
);
2385 TRACE("(%p) : Idx(%d), pLight(%p)\n", This
, Index
, pLight
);
2387 LIST_FOR_EACH(e
, &This
->stateBlock
->lightMap
[Hi
])
2389 lightInfo
= LIST_ENTRY(e
, struct wined3d_light_info
, entry
);
2390 if(lightInfo
->OriginalIndex
== Index
) break;
2394 if (lightInfo
== NULL
) {
2395 TRACE("Light information requested but light not defined\n");
2396 return WINED3DERR_INVALIDCALL
;
2399 *pLight
= lightInfo
->OriginalParms
;
2404 * Get / Set Light Enable
2405 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2407 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice
*iface
, DWORD Index
, BOOL Enable
)
2409 struct wined3d_light_info
*lightInfo
= NULL
;
2410 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2411 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2413 TRACE("(%p) : Idx(%d), enable? %d\n", This
, Index
, Enable
);
2415 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
])
2417 lightInfo
= LIST_ENTRY(e
, struct wined3d_light_info
, entry
);
2418 if(lightInfo
->OriginalIndex
== Index
) break;
2421 TRACE("Found light: %p\n", lightInfo
);
2423 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2424 if (lightInfo
== NULL
) {
2426 TRACE("Light enabled requested but light not defined, so defining one!\n");
2427 IWineD3DDeviceImpl_SetLight(iface
, Index
, &WINED3D_default_light
);
2429 /* Search for it again! Should be fairly quick as near head of list */
2430 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
])
2432 lightInfo
= LIST_ENTRY(e
, struct wined3d_light_info
, entry
);
2433 if(lightInfo
->OriginalIndex
== Index
) break;
2436 if (lightInfo
== NULL
) {
2437 FIXME("Adding default lights has failed dismally\n");
2438 return WINED3DERR_INVALIDCALL
;
2443 if(lightInfo
->glIndex
!= -1) {
2444 if(!This
->isRecordingState
) {
2445 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(lightInfo
->glIndex
));
2448 This
->updateStateBlock
->activeLights
[lightInfo
->glIndex
] = NULL
;
2449 lightInfo
->glIndex
= -1;
2451 TRACE("Light already disabled, nothing to do\n");
2453 lightInfo
->enabled
= FALSE
;
2455 lightInfo
->enabled
= TRUE
;
2456 if (lightInfo
->glIndex
!= -1) {
2458 TRACE("Nothing to do as light was enabled\n");
2461 /* Find a free gl light */
2462 for(i
= 0; i
< This
->maxConcurrentLights
; i
++) {
2463 if(This
->updateStateBlock
->activeLights
[i
] == NULL
) {
2464 This
->updateStateBlock
->activeLights
[i
] = lightInfo
;
2465 lightInfo
->glIndex
= i
;
2469 if(lightInfo
->glIndex
== -1) {
2470 /* Our tests show that Windows returns D3D_OK in this situation, even with
2471 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2472 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2473 * as well for those lights.
2475 * TODO: Test how this affects rendering
2477 WARN("Too many concurrently active lights\n");
2481 /* i == lightInfo->glIndex */
2482 if(!This
->isRecordingState
) {
2483 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(i
));
2491 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice
*iface
, DWORD Index
,BOOL
* pEnable
)
2493 struct wined3d_light_info
*lightInfo
= NULL
;
2494 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2496 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2497 TRACE("(%p) : for idx(%d)\n", This
, Index
);
2499 LIST_FOR_EACH(e
, &This
->stateBlock
->lightMap
[Hi
])
2501 lightInfo
= LIST_ENTRY(e
, struct wined3d_light_info
, entry
);
2502 if(lightInfo
->OriginalIndex
== Index
) break;
2506 if (lightInfo
== NULL
) {
2507 TRACE("Light enabled state requested but light not defined\n");
2508 return WINED3DERR_INVALIDCALL
;
2510 /* true is 128 according to SetLightEnable */
2511 *pEnable
= lightInfo
->enabled
? 128 : 0;
2516 * Get / Set Clip Planes
2518 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, CONST
float *pPlane
) {
2519 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2520 TRACE("(%p) : for idx %d, %p\n", This
, Index
, pPlane
);
2522 /* Validate Index */
2523 if (Index
>= This
->adapter
->gl_info
.limits
.clipplanes
)
2525 TRACE("Application has requested clipplane this device doesn't support\n");
2526 return WINED3DERR_INVALIDCALL
;
2529 This
->updateStateBlock
->changed
.clipplane
|= 1 << Index
;
2531 if(This
->updateStateBlock
->clipplane
[Index
][0] == pPlane
[0] &&
2532 This
->updateStateBlock
->clipplane
[Index
][1] == pPlane
[1] &&
2533 This
->updateStateBlock
->clipplane
[Index
][2] == pPlane
[2] &&
2534 This
->updateStateBlock
->clipplane
[Index
][3] == pPlane
[3]) {
2535 TRACE("Application is setting old values over, nothing to do\n");
2539 This
->updateStateBlock
->clipplane
[Index
][0] = pPlane
[0];
2540 This
->updateStateBlock
->clipplane
[Index
][1] = pPlane
[1];
2541 This
->updateStateBlock
->clipplane
[Index
][2] = pPlane
[2];
2542 This
->updateStateBlock
->clipplane
[Index
][3] = pPlane
[3];
2544 /* Handle recording of state blocks */
2545 if (This
->isRecordingState
) {
2546 TRACE("Recording... not performing anything\n");
2550 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_CLIPPLANE(Index
));
2555 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, float *pPlane
) {
2556 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2557 TRACE("(%p) : for idx %d\n", This
, Index
);
2559 /* Validate Index */
2560 if (Index
>= This
->adapter
->gl_info
.limits
.clipplanes
)
2562 TRACE("Application has requested clipplane this device doesn't support\n");
2563 return WINED3DERR_INVALIDCALL
;
2566 pPlane
[0] = This
->stateBlock
->clipplane
[Index
][0];
2567 pPlane
[1] = This
->stateBlock
->clipplane
[Index
][1];
2568 pPlane
[2] = This
->stateBlock
->clipplane
[Index
][2];
2569 pPlane
[3] = This
->stateBlock
->clipplane
[Index
][3];
2574 * Get / Set Clip Plane Status
2575 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2577 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice
*iface
, CONST WINED3DCLIPSTATUS
* pClipStatus
) {
2578 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2579 FIXME("(%p) : stub\n", This
);
2580 if (NULL
== pClipStatus
) {
2581 return WINED3DERR_INVALIDCALL
;
2583 This
->updateStateBlock
->clip_status
.ClipUnion
= pClipStatus
->ClipUnion
;
2584 This
->updateStateBlock
->clip_status
.ClipIntersection
= pClipStatus
->ClipIntersection
;
2588 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice
*iface
, WINED3DCLIPSTATUS
* pClipStatus
) {
2589 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2590 FIXME("(%p) : stub\n", This
);
2591 if (NULL
== pClipStatus
) {
2592 return WINED3DERR_INVALIDCALL
;
2594 pClipStatus
->ClipUnion
= This
->updateStateBlock
->clip_status
.ClipUnion
;
2595 pClipStatus
->ClipIntersection
= This
->updateStateBlock
->clip_status
.ClipIntersection
;
2600 * Get / Set Material
2602 static HRESULT WINAPI
IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice
*iface
, CONST WINED3DMATERIAL
* pMaterial
) {
2603 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2605 This
->updateStateBlock
->changed
.material
= TRUE
;
2606 This
->updateStateBlock
->material
= *pMaterial
;
2608 /* Handle recording of state blocks */
2609 if (This
->isRecordingState
) {
2610 TRACE("Recording... not performing anything\n");
2614 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_MATERIAL
);
2618 static HRESULT WINAPI
IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice
*iface
, WINED3DMATERIAL
* pMaterial
) {
2619 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2620 *pMaterial
= This
->updateStateBlock
->material
;
2621 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This
, pMaterial
->Diffuse
.r
, pMaterial
->Diffuse
.g
,
2622 pMaterial
->Diffuse
.b
, pMaterial
->Diffuse
.a
);
2623 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This
, pMaterial
->Ambient
.r
, pMaterial
->Ambient
.g
,
2624 pMaterial
->Ambient
.b
, pMaterial
->Ambient
.a
);
2625 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This
, pMaterial
->Specular
.r
, pMaterial
->Specular
.g
,
2626 pMaterial
->Specular
.b
, pMaterial
->Specular
.a
);
2627 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This
, pMaterial
->Emissive
.r
, pMaterial
->Emissive
.g
,
2628 pMaterial
->Emissive
.b
, pMaterial
->Emissive
.a
);
2629 TRACE("(%p) : Power (%f)\n", This
, pMaterial
->Power
);
2637 static HRESULT WINAPI
IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice
*iface
,
2638 IWineD3DBuffer
*pIndexData
, WINED3DFORMAT fmt
)
2640 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2641 IWineD3DBuffer
*oldIdxs
;
2643 TRACE("(%p) : Setting to %p\n", This
, pIndexData
);
2644 oldIdxs
= This
->updateStateBlock
->pIndexData
;
2646 This
->updateStateBlock
->changed
.indices
= TRUE
;
2647 This
->updateStateBlock
->pIndexData
= pIndexData
;
2648 This
->updateStateBlock
->IndexFmt
= fmt
;
2650 /* Handle recording of state blocks */
2651 if (This
->isRecordingState
) {
2652 TRACE("Recording... not performing anything\n");
2653 if(pIndexData
) IWineD3DBuffer_AddRef(pIndexData
);
2654 if(oldIdxs
) IWineD3DBuffer_Release(oldIdxs
);
2658 if(oldIdxs
!= pIndexData
) {
2659 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
2661 InterlockedIncrement(&((struct wined3d_buffer
*)pIndexData
)->bind_count
);
2662 IWineD3DBuffer_AddRef(pIndexData
);
2665 InterlockedDecrement(&((struct wined3d_buffer
*)oldIdxs
)->bind_count
);
2666 IWineD3DBuffer_Release(oldIdxs
);
2673 static HRESULT WINAPI
IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice
*iface
, IWineD3DBuffer
**ppIndexData
)
2675 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2677 *ppIndexData
= This
->stateBlock
->pIndexData
;
2679 /* up ref count on ppindexdata */
2681 IWineD3DBuffer_AddRef(*ppIndexData
);
2682 TRACE("(%p) index data set to %p\n", This
, ppIndexData
);
2684 TRACE("(%p) No index data set\n", This
);
2686 TRACE("Returning %p\n", *ppIndexData
);
2691 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2692 static HRESULT WINAPI
IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice
*iface
, INT BaseIndex
) {
2693 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2694 TRACE("(%p)->(%d)\n", This
, BaseIndex
);
2696 if(This
->updateStateBlock
->baseVertexIndex
== BaseIndex
) {
2697 TRACE("Application is setting the old value over, nothing to do\n");
2701 This
->updateStateBlock
->baseVertexIndex
= BaseIndex
;
2703 if (This
->isRecordingState
) {
2704 TRACE("Recording... not performing anything\n");
2707 /* The base vertex index affects the stream sources */
2708 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2712 static HRESULT WINAPI
IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice
*iface
, INT
* base_index
) {
2713 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2714 TRACE("(%p) : base_index %p\n", This
, base_index
);
2716 *base_index
= This
->stateBlock
->baseVertexIndex
;
2718 TRACE("Returning %u\n", *base_index
);
2724 * Get / Set Viewports
2726 static HRESULT WINAPI
IWineD3DDeviceImpl_SetViewport(IWineD3DDevice
*iface
, CONST WINED3DVIEWPORT
* pViewport
) {
2727 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2729 TRACE("(%p)\n", This
);
2730 This
->updateStateBlock
->changed
.viewport
= TRUE
;
2731 This
->updateStateBlock
->viewport
= *pViewport
;
2733 /* Handle recording of state blocks */
2734 if (This
->isRecordingState
) {
2735 TRACE("Recording... not performing anything\n");
2739 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This
,
2740 pViewport
->X
, pViewport
->Y
, pViewport
->Width
, pViewport
->Height
, pViewport
->MinZ
, pViewport
->MaxZ
);
2742 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VIEWPORT
);
2747 static HRESULT WINAPI
IWineD3DDeviceImpl_GetViewport(IWineD3DDevice
*iface
, WINED3DVIEWPORT
* pViewport
) {
2748 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2749 TRACE("(%p)\n", This
);
2750 *pViewport
= This
->stateBlock
->viewport
;
2755 * Get / Set Render States
2756 * TODO: Verify against dx9 definitions
2758 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice
*iface
, WINED3DRENDERSTATETYPE State
, DWORD Value
) {
2760 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2761 DWORD oldValue
= This
->stateBlock
->renderState
[State
];
2763 TRACE("(%p)->state = %s(%d), value = %d\n", This
, debug_d3drenderstate(State
), State
, Value
);
2765 This
->updateStateBlock
->changed
.renderState
[State
>> 5] |= 1 << (State
& 0x1f);
2766 This
->updateStateBlock
->renderState
[State
] = Value
;
2768 /* Handle recording of state blocks */
2769 if (This
->isRecordingState
) {
2770 TRACE("Recording... not performing anything\n");
2774 /* Compared here and not before the assignment to allow proper stateblock recording */
2775 if(Value
== oldValue
) {
2776 TRACE("Application is setting the old value over, nothing to do\n");
2778 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(State
));
2784 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice
*iface
, WINED3DRENDERSTATETYPE State
, DWORD
*pValue
) {
2785 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2786 TRACE("(%p) for State %d = %d\n", This
, State
, This
->stateBlock
->renderState
[State
]);
2787 *pValue
= This
->stateBlock
->renderState
[State
];
2792 * Get / Set Sampler States
2793 * TODO: Verify against dx9 definitions
2796 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD Value
) {
2797 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2800 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2801 This
, Sampler
, debug_d3dsamplerstate(Type
), Type
, Value
);
2803 if (Sampler
>= WINED3DVERTEXTEXTURESAMPLER0
&& Sampler
<= WINED3DVERTEXTEXTURESAMPLER3
) {
2804 Sampler
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
2807 if (Sampler
>= sizeof(This
->stateBlock
->samplerState
)/sizeof(This
->stateBlock
->samplerState
[0])) {
2808 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler
);
2809 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
2812 * SetSampler is designed to allow for more than the standard up to 8 textures
2813 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2814 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2816 * http://developer.nvidia.com/object/General_FAQ.html#t6
2818 * There are two new settings for GForce
2820 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2821 * and the texture one:
2822 * GL_MAX_TEXTURE_COORDS_ARB.
2823 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2826 oldValue
= This
->stateBlock
->samplerState
[Sampler
][Type
];
2827 This
->updateStateBlock
->samplerState
[Sampler
][Type
] = Value
;
2828 This
->updateStateBlock
->changed
.samplerState
[Sampler
] |= 1 << Type
;
2830 /* Handle recording of state blocks */
2831 if (This
->isRecordingState
) {
2832 TRACE("Recording... not performing anything\n");
2836 if(oldValue
== Value
) {
2837 TRACE("Application is setting the old value over, nothing to do\n");
2841 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(Sampler
));
2846 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD
* Value
) {
2847 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2849 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2850 This
, Sampler
, debug_d3dsamplerstate(Type
), Type
);
2852 if (Sampler
>= WINED3DVERTEXTEXTURESAMPLER0
&& Sampler
<= WINED3DVERTEXTEXTURESAMPLER3
) {
2853 Sampler
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
2856 if (Sampler
>= sizeof(This
->stateBlock
->samplerState
)/sizeof(This
->stateBlock
->samplerState
[0])) {
2857 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler
);
2858 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
2860 *Value
= This
->stateBlock
->samplerState
[Sampler
][Type
];
2861 TRACE("(%p) : Returning %#x\n", This
, *Value
);
2866 static HRESULT WINAPI
IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice
*iface
, CONST RECT
* pRect
) {
2867 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2869 This
->updateStateBlock
->changed
.scissorRect
= TRUE
;
2870 if(EqualRect(&This
->updateStateBlock
->scissorRect
, pRect
)) {
2871 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2874 CopyRect(&This
->updateStateBlock
->scissorRect
, pRect
);
2876 if(This
->isRecordingState
) {
2877 TRACE("Recording... not performing anything\n");
2881 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SCISSORRECT
);
2886 static HRESULT WINAPI
IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice
*iface
, RECT
* pRect
) {
2887 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2889 *pRect
= This
->updateStateBlock
->scissorRect
;
2890 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This
, pRect
->left
, pRect
->top
, pRect
->right
, pRect
->bottom
);
2894 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
* pDecl
) {
2895 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2896 IWineD3DVertexDeclaration
*oldDecl
= This
->updateStateBlock
->vertexDecl
;
2898 TRACE("(%p) : pDecl=%p\n", This
, pDecl
);
2900 if (pDecl
) IWineD3DVertexDeclaration_AddRef(pDecl
);
2901 if (oldDecl
) IWineD3DVertexDeclaration_Release(oldDecl
);
2903 This
->updateStateBlock
->vertexDecl
= pDecl
;
2904 This
->updateStateBlock
->changed
.vertexDecl
= TRUE
;
2906 if (This
->isRecordingState
) {
2907 TRACE("Recording... not performing anything\n");
2909 } else if(pDecl
== oldDecl
) {
2910 /* Checked after the assignment to allow proper stateblock recording */
2911 TRACE("Application is setting the old declaration over, nothing to do\n");
2915 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
2919 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppDecl
) {
2920 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2922 TRACE("(%p) : ppDecl=%p\n", This
, ppDecl
);
2924 *ppDecl
= This
->stateBlock
->vertexDecl
;
2925 if (NULL
!= *ppDecl
) IWineD3DVertexDeclaration_AddRef(*ppDecl
);
2929 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
* pShader
) {
2930 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2931 IWineD3DVertexShader
* oldShader
= This
->updateStateBlock
->vertexShader
;
2933 This
->updateStateBlock
->vertexShader
= pShader
;
2934 This
->updateStateBlock
->changed
.vertexShader
= TRUE
;
2936 if (This
->isRecordingState
) {
2937 if(pShader
) IWineD3DVertexShader_AddRef(pShader
);
2938 if(oldShader
) IWineD3DVertexShader_Release(oldShader
);
2939 TRACE("Recording... not performing anything\n");
2941 } else if(oldShader
== pShader
) {
2942 /* Checked here to allow proper stateblock recording */
2943 TRACE("App is setting the old shader over, nothing to do\n");
2947 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
2948 if(pShader
) IWineD3DVertexShader_AddRef(pShader
);
2949 if(oldShader
) IWineD3DVertexShader_Release(oldShader
);
2951 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VSHADER
);
2956 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
** ppShader
) {
2957 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2959 if (NULL
== ppShader
) {
2960 return WINED3DERR_INVALIDCALL
;
2962 *ppShader
= This
->stateBlock
->vertexShader
;
2963 if( NULL
!= *ppShader
)
2964 IWineD3DVertexShader_AddRef(*ppShader
);
2966 TRACE("(%p) : returning %p\n", This
, *ppShader
);
2970 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantB(
2971 IWineD3DDevice
*iface
,
2973 CONST BOOL
*srcData
,
2976 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2977 unsigned int i
, cnt
= min(count
, MAX_CONST_B
- start
);
2979 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2980 iface
, srcData
, start
, count
);
2982 if (!srcData
|| start
>= MAX_CONST_B
) return WINED3DERR_INVALIDCALL
;
2984 memcpy(&This
->updateStateBlock
->vertexShaderConstantB
[start
], srcData
, cnt
* sizeof(BOOL
));
2985 for (i
= 0; i
< cnt
; i
++)
2986 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
2988 for (i
= start
; i
< cnt
+ start
; ++i
) {
2989 This
->updateStateBlock
->changed
.vertexShaderConstantsB
|= (1 << i
);
2992 if (!This
->isRecordingState
) IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
2997 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantB(
2998 IWineD3DDevice
*iface
,
3003 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3004 int cnt
= min(count
, MAX_CONST_B
- start
);
3006 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3007 iface
, dstData
, start
, count
);
3009 if (dstData
== NULL
|| cnt
< 0)
3010 return WINED3DERR_INVALIDCALL
;
3012 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantB
[start
], cnt
* sizeof(BOOL
));
3016 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantI(
3017 IWineD3DDevice
*iface
,
3022 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3023 unsigned int i
, cnt
= min(count
, MAX_CONST_I
- start
);
3025 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3026 iface
, srcData
, start
, count
);
3028 if (!srcData
|| start
>= MAX_CONST_I
) return WINED3DERR_INVALIDCALL
;
3030 memcpy(&This
->updateStateBlock
->vertexShaderConstantI
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
3031 for (i
= 0; i
< cnt
; i
++)
3032 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
3033 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3035 for (i
= start
; i
< cnt
+ start
; ++i
) {
3036 This
->updateStateBlock
->changed
.vertexShaderConstantsI
|= (1 << i
);
3039 if (!This
->isRecordingState
) IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3044 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantI(
3045 IWineD3DDevice
*iface
,
3050 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3051 int cnt
= min(count
, MAX_CONST_I
- start
);
3053 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3054 iface
, dstData
, start
, count
);
3056 if (dstData
== NULL
|| ((signed int) MAX_CONST_I
- (signed int) start
) <= 0)
3057 return WINED3DERR_INVALIDCALL
;
3059 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantI
[start
* 4], cnt
* sizeof(int) * 4);
3063 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantF(
3064 IWineD3DDevice
*iface
,
3066 CONST
float *srcData
,
3069 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3072 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3073 iface
, srcData
, start
, count
);
3075 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3076 if (srcData
== NULL
|| start
+ count
> This
->d3d_vshader_constantF
|| start
> This
->d3d_vshader_constantF
)
3077 return WINED3DERR_INVALIDCALL
;
3079 memcpy(&This
->updateStateBlock
->vertexShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
3081 for (i
= 0; i
< count
; i
++)
3082 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
3083 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3086 if (!This
->isRecordingState
)
3088 This
->shader_backend
->shader_update_float_vertex_constants(iface
, start
, count
);
3089 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3092 memset(This
->updateStateBlock
->changed
.vertexShaderConstantsF
+ start
, 1,
3093 sizeof(*This
->updateStateBlock
->changed
.vertexShaderConstantsF
) * count
);
3098 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantF(
3099 IWineD3DDevice
*iface
,
3104 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3105 int cnt
= min(count
, This
->d3d_vshader_constantF
- start
);
3107 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3108 iface
, dstData
, start
, count
);
3110 if (dstData
== NULL
|| cnt
< 0)
3111 return WINED3DERR_INVALIDCALL
;
3113 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantF
[start
* 4], cnt
* sizeof(float) * 4);
3117 static inline void markTextureStagesDirty(IWineD3DDeviceImpl
*This
, DWORD stage
) {
3119 for(i
= 0; i
<= WINED3D_HIGHEST_TEXTURE_STATE
; ++i
)
3121 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, i
));
3125 static void device_map_stage(IWineD3DDeviceImpl
*This
, DWORD stage
, DWORD unit
)
3127 DWORD i
= This
->rev_tex_unit_map
[unit
];
3128 DWORD j
= This
->texUnitMap
[stage
];
3130 This
->texUnitMap
[stage
] = unit
;
3131 if (i
!= WINED3D_UNMAPPED_STAGE
&& i
!= stage
)
3133 This
->texUnitMap
[i
] = WINED3D_UNMAPPED_STAGE
;
3136 This
->rev_tex_unit_map
[unit
] = stage
;
3137 if (j
!= WINED3D_UNMAPPED_STAGE
&& j
!= unit
)
3139 This
->rev_tex_unit_map
[j
] = WINED3D_UNMAPPED_STAGE
;
3143 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl
*This
) {
3146 This
->fixed_function_usage_map
= 0;
3147 for (i
= 0; i
< MAX_TEXTURES
; ++i
) {
3148 WINED3DTEXTUREOP color_op
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLOROP
];
3149 WINED3DTEXTUREOP alpha_op
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAOP
];
3150 DWORD color_arg1
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG1
] & WINED3DTA_SELECTMASK
;
3151 DWORD color_arg2
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG2
] & WINED3DTA_SELECTMASK
;
3152 DWORD color_arg3
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG0
] & WINED3DTA_SELECTMASK
;
3153 DWORD alpha_arg1
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG1
] & WINED3DTA_SELECTMASK
;
3154 DWORD alpha_arg2
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG2
] & WINED3DTA_SELECTMASK
;
3155 DWORD alpha_arg3
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG0
] & WINED3DTA_SELECTMASK
;
3157 if (color_op
== WINED3DTOP_DISABLE
) {
3158 /* Not used, and disable higher stages */
3162 if (((color_arg1
== WINED3DTA_TEXTURE
) && color_op
!= WINED3DTOP_SELECTARG2
)
3163 || ((color_arg2
== WINED3DTA_TEXTURE
) && color_op
!= WINED3DTOP_SELECTARG1
)
3164 || ((color_arg3
== WINED3DTA_TEXTURE
) && (color_op
== WINED3DTOP_MULTIPLYADD
|| color_op
== WINED3DTOP_LERP
))
3165 || ((alpha_arg1
== WINED3DTA_TEXTURE
) && alpha_op
!= WINED3DTOP_SELECTARG2
)
3166 || ((alpha_arg2
== WINED3DTA_TEXTURE
) && alpha_op
!= WINED3DTOP_SELECTARG1
)
3167 || ((alpha_arg3
== WINED3DTA_TEXTURE
) && (alpha_op
== WINED3DTOP_MULTIPLYADD
|| alpha_op
== WINED3DTOP_LERP
))) {
3168 This
->fixed_function_usage_map
|= (1 << i
);
3171 if ((color_op
== WINED3DTOP_BUMPENVMAP
|| color_op
== WINED3DTOP_BUMPENVMAPLUMINANCE
) && i
< MAX_TEXTURES
- 1) {
3172 This
->fixed_function_usage_map
|= (1 << (i
+ 1));
3177 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl
*This
, const struct wined3d_gl_info
*gl_info
)
3179 unsigned int i
, tex
;
3182 device_update_fixed_function_usage_map(This
);
3183 ffu_map
= This
->fixed_function_usage_map
;
3185 if (This
->max_ffp_textures
== gl_info
->limits
.texture_stages
3186 || This
->stateBlock
->lowest_disabled_stage
<= This
->max_ffp_textures
)
3188 for (i
= 0; ffu_map
; ffu_map
>>= 1, ++i
)
3190 if (!(ffu_map
& 1)) continue;
3192 if (This
->texUnitMap
[i
] != i
) {
3193 device_map_stage(This
, i
, i
);
3194 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3195 markTextureStagesDirty(This
, i
);
3201 /* Now work out the mapping */
3203 for (i
= 0; ffu_map
; ffu_map
>>= 1, ++i
)
3205 if (!(ffu_map
& 1)) continue;
3207 if (This
->texUnitMap
[i
] != tex
) {
3208 device_map_stage(This
, i
, tex
);
3209 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3210 markTextureStagesDirty(This
, i
);
3217 static void device_map_psamplers(IWineD3DDeviceImpl
*This
, const struct wined3d_gl_info
*gl_info
)
3219 const WINED3DSAMPLER_TEXTURE_TYPE
*sampler_type
=
3220 ((IWineD3DPixelShaderImpl
*)This
->stateBlock
->pixelShader
)->baseShader
.reg_maps
.sampler_type
;
3223 for (i
= 0; i
< MAX_FRAGMENT_SAMPLERS
; ++i
) {
3224 if (sampler_type
[i
] && This
->texUnitMap
[i
] != i
)
3226 device_map_stage(This
, i
, i
);
3227 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3228 if (i
< gl_info
->limits
.texture_stages
)
3230 markTextureStagesDirty(This
, i
);
3236 static BOOL
device_unit_free_for_vs(IWineD3DDeviceImpl
*This
, const DWORD
*pshader_sampler_tokens
,
3237 const DWORD
*vshader_sampler_tokens
, DWORD unit
)
3239 DWORD current_mapping
= This
->rev_tex_unit_map
[unit
];
3241 /* Not currently used */
3242 if (current_mapping
== WINED3D_UNMAPPED_STAGE
) return TRUE
;
3244 if (current_mapping
< MAX_FRAGMENT_SAMPLERS
) {
3245 /* Used by a fragment sampler */
3247 if (!pshader_sampler_tokens
) {
3248 /* No pixel shader, check fixed function */
3249 return current_mapping
>= MAX_TEXTURES
|| !(This
->fixed_function_usage_map
& (1 << current_mapping
));
3252 /* Pixel shader, check the shader's sampler map */
3253 return !pshader_sampler_tokens
[current_mapping
];
3256 /* Used by a vertex sampler */
3257 return !vshader_sampler_tokens
[current_mapping
- MAX_FRAGMENT_SAMPLERS
];
3260 static void device_map_vsamplers(IWineD3DDeviceImpl
*This
, BOOL ps
, const struct wined3d_gl_info
*gl_info
)
3262 const WINED3DSAMPLER_TEXTURE_TYPE
*vshader_sampler_type
=
3263 ((IWineD3DVertexShaderImpl
*)This
->stateBlock
->vertexShader
)->baseShader
.reg_maps
.sampler_type
;
3264 const WINED3DSAMPLER_TEXTURE_TYPE
*pshader_sampler_type
= NULL
;
3265 int start
= min(MAX_COMBINED_SAMPLERS
, gl_info
->limits
.combined_samplers
) - 1;
3269 IWineD3DPixelShaderImpl
*pshader
= (IWineD3DPixelShaderImpl
*)This
->stateBlock
->pixelShader
;
3271 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3272 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3273 pshader_sampler_type
= pshader
->baseShader
.reg_maps
.sampler_type
;
3276 for (i
= 0; i
< MAX_VERTEX_SAMPLERS
; ++i
) {
3277 DWORD vsampler_idx
= i
+ MAX_FRAGMENT_SAMPLERS
;
3278 if (vshader_sampler_type
[i
])
3280 if (This
->texUnitMap
[vsampler_idx
] != WINED3D_UNMAPPED_STAGE
)
3282 /* Already mapped somewhere */
3286 while (start
>= 0) {
3287 if (device_unit_free_for_vs(This
, pshader_sampler_type
, vshader_sampler_type
, start
))
3289 device_map_stage(This
, vsampler_idx
, start
);
3290 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(vsampler_idx
));
3302 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl
*This
)
3304 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
3305 BOOL vs
= use_vs(This
->stateBlock
);
3306 BOOL ps
= use_ps(This
->stateBlock
);
3309 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3310 * that would be really messy and require shader recompilation
3311 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3312 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3314 if (ps
) device_map_psamplers(This
, gl_info
);
3315 else device_map_fixed_function_samplers(This
, gl_info
);
3317 if (vs
) device_map_vsamplers(This
, ps
, gl_info
);
3320 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
*pShader
) {
3321 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3322 IWineD3DPixelShader
*oldShader
= This
->updateStateBlock
->pixelShader
;
3323 This
->updateStateBlock
->pixelShader
= pShader
;
3324 This
->updateStateBlock
->changed
.pixelShader
= TRUE
;
3326 /* Handle recording of state blocks */
3327 if (This
->isRecordingState
) {
3328 TRACE("Recording... not performing anything\n");
3331 if (This
->isRecordingState
) {
3332 TRACE("Recording... not performing anything\n");
3333 if(pShader
) IWineD3DPixelShader_AddRef(pShader
);
3334 if(oldShader
) IWineD3DPixelShader_Release(oldShader
);
3338 if(pShader
== oldShader
) {
3339 TRACE("App is setting the old pixel shader over, nothing to do\n");
3343 if(pShader
) IWineD3DPixelShader_AddRef(pShader
);
3344 if(oldShader
) IWineD3DPixelShader_Release(oldShader
);
3346 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
3347 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADER
);
3352 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
**ppShader
) {
3353 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3355 if (NULL
== ppShader
) {
3356 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This
);
3357 return WINED3DERR_INVALIDCALL
;
3360 *ppShader
= This
->stateBlock
->pixelShader
;
3361 if (NULL
!= *ppShader
) {
3362 IWineD3DPixelShader_AddRef(*ppShader
);
3364 TRACE("(%p) : returning %p\n", This
, *ppShader
);
3368 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantB(
3369 IWineD3DDevice
*iface
,
3371 CONST BOOL
*srcData
,
3374 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3375 unsigned int i
, cnt
= min(count
, MAX_CONST_B
- start
);
3377 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3378 iface
, srcData
, start
, count
);
3380 if (!srcData
|| start
>= MAX_CONST_B
) return WINED3DERR_INVALIDCALL
;
3382 memcpy(&This
->updateStateBlock
->pixelShaderConstantB
[start
], srcData
, cnt
* sizeof(BOOL
));
3383 for (i
= 0; i
< cnt
; i
++)
3384 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
3386 for (i
= start
; i
< cnt
+ start
; ++i
) {
3387 This
->updateStateBlock
->changed
.pixelShaderConstantsB
|= (1 << i
);
3390 if (!This
->isRecordingState
) IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3395 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantB(
3396 IWineD3DDevice
*iface
,
3401 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3402 int cnt
= min(count
, MAX_CONST_B
- start
);
3404 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3405 iface
, dstData
, start
, count
);
3407 if (dstData
== NULL
|| cnt
< 0)
3408 return WINED3DERR_INVALIDCALL
;
3410 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantB
[start
], cnt
* sizeof(BOOL
));
3414 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantI(
3415 IWineD3DDevice
*iface
,
3420 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3421 unsigned int i
, cnt
= min(count
, MAX_CONST_I
- start
);
3423 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3424 iface
, srcData
, start
, count
);
3426 if (!srcData
|| start
>= MAX_CONST_I
) return WINED3DERR_INVALIDCALL
;
3428 memcpy(&This
->updateStateBlock
->pixelShaderConstantI
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
3429 for (i
= 0; i
< cnt
; i
++)
3430 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
3431 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3433 for (i
= start
; i
< cnt
+ start
; ++i
) {
3434 This
->updateStateBlock
->changed
.pixelShaderConstantsI
|= (1 << i
);
3437 if (!This
->isRecordingState
) IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3442 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantI(
3443 IWineD3DDevice
*iface
,
3448 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3449 int cnt
= min(count
, MAX_CONST_I
- start
);
3451 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3452 iface
, dstData
, start
, count
);
3454 if (dstData
== NULL
|| cnt
< 0)
3455 return WINED3DERR_INVALIDCALL
;
3457 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantI
[start
* 4], cnt
* sizeof(int) * 4);
3461 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantF(
3462 IWineD3DDevice
*iface
,
3464 CONST
float *srcData
,
3467 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3470 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3471 iface
, srcData
, start
, count
);
3473 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3474 if (srcData
== NULL
|| start
+ count
> This
->d3d_pshader_constantF
|| start
> This
->d3d_pshader_constantF
)
3475 return WINED3DERR_INVALIDCALL
;
3477 memcpy(&This
->updateStateBlock
->pixelShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
3479 for (i
= 0; i
< count
; i
++)
3480 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
3481 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3484 if (!This
->isRecordingState
)
3486 This
->shader_backend
->shader_update_float_pixel_constants(iface
, start
, count
);
3487 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3490 memset(This
->updateStateBlock
->changed
.pixelShaderConstantsF
+ start
, 1,
3491 sizeof(*This
->updateStateBlock
->changed
.pixelShaderConstantsF
) * count
);
3496 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantF(
3497 IWineD3DDevice
*iface
,
3502 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3503 int cnt
= min(count
, This
->d3d_pshader_constantF
- start
);
3505 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3506 iface
, dstData
, start
, count
);
3508 if (dstData
== NULL
|| cnt
< 0)
3509 return WINED3DERR_INVALIDCALL
;
3511 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantF
[start
* 4], cnt
* sizeof(float) * 4);
3515 /* Context activation is done by the caller. */
3516 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3517 static HRESULT
process_vertices_strided(IWineD3DDeviceImpl
*This
, DWORD dwDestIndex
, DWORD dwCount
,
3518 const struct wined3d_stream_info
*stream_info
, struct wined3d_buffer
*dest
, DWORD dwFlags
,
3521 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
3522 char *dest_ptr
, *dest_conv
= NULL
, *dest_conv_addr
= NULL
;
3525 WINED3DMATRIX mat
, proj_mat
, view_mat
, world_mat
;
3529 if (stream_info
->use_map
& (1 << WINED3D_FFP_NORMAL
))
3531 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3534 if (!(stream_info
->use_map
& (1 << WINED3D_FFP_POSITION
)))
3536 ERR("Source has no position mask\n");
3537 return WINED3DERR_INVALIDCALL
;
3540 /* We might access VBOs from this code, so hold the lock */
3543 if (dest
->resource
.allocatedMemory
== NULL
) {
3544 buffer_get_sysmem(dest
);
3547 /* Get a pointer into the destination vbo(create one if none exists) and
3548 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3550 if (!dest
->buffer_object
&& gl_info
->supported
[ARB_VERTEX_BUFFER_OBJECT
])
3552 dest
->flags
|= WINED3D_BUFFER_CREATEBO
;
3553 IWineD3DBuffer_PreLoad((IWineD3DBuffer
*)dest
);
3556 if (dest
->buffer_object
)
3558 unsigned char extrabytes
= 0;
3559 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3560 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3561 * this may write 4 extra bytes beyond the area that should be written
3563 if(DestFVF
== WINED3DFVF_XYZ
) extrabytes
= 4;
3564 dest_conv_addr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwCount
* get_flexible_vertex_size(DestFVF
) + extrabytes
);
3565 if(!dest_conv_addr
) {
3566 ERR("Out of memory\n");
3567 /* Continue without storing converted vertices */
3569 dest_conv
= dest_conv_addr
;
3573 * a) WINED3DRS_CLIPPING is enabled
3574 * b) WINED3DVOP_CLIP is passed
3576 if(This
->stateBlock
->renderState
[WINED3DRS_CLIPPING
]) {
3577 static BOOL warned
= FALSE
;
3579 * The clipping code is not quite correct. Some things need
3580 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3581 * so disable clipping for now.
3582 * (The graphics in Half-Life are broken, and my processvertices
3583 * test crashes with IDirect3DDevice3)
3589 FIXME("Clipping is broken and disabled for now\n");
3591 } else doClip
= FALSE
;
3592 dest_ptr
= ((char *) buffer_get_sysmem(dest
)) + dwDestIndex
* get_flexible_vertex_size(DestFVF
);
3594 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
3597 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
3598 WINED3DTS_PROJECTION
,
3600 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
3601 WINED3DTS_WORLDMATRIX(0),
3604 TRACE("View mat:\n");
3605 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
);
3606 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
);
3607 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
);
3608 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
);
3610 TRACE("Proj mat:\n");
3611 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
);
3612 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
);
3613 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
);
3614 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
);
3616 TRACE("World mat:\n");
3617 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
);
3618 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
);
3619 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
);
3620 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
);
3622 /* Get the viewport */
3623 IWineD3DDevice_GetViewport( (IWineD3DDevice
*) This
, &vp
);
3624 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3625 vp
.X
, vp
.Y
, vp
.Width
, vp
.Height
, vp
.MinZ
, vp
.MaxZ
);
3627 multiply_matrix(&mat
,&view_mat
,&world_mat
);
3628 multiply_matrix(&mat
,&proj_mat
,&mat
);
3630 numTextures
= (DestFVF
& WINED3DFVF_TEXCOUNT_MASK
) >> WINED3DFVF_TEXCOUNT_SHIFT
;
3632 for (i
= 0; i
< dwCount
; i
+= 1) {
3633 unsigned int tex_index
;
3635 if ( ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZ
) ||
3636 ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) ) {
3637 /* The position first */
3638 const struct wined3d_stream_info_element
*element
= &stream_info
->elements
[WINED3D_FFP_POSITION
];
3639 const float *p
= (const float *)(element
->data
+ i
* element
->stride
);
3641 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p
[0], p
[1], p
[2]);
3643 /* Multiplication with world, view and projection matrix */
3644 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
);
3645 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
);
3646 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
);
3647 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
);
3649 TRACE("x=%f y=%f z=%f rhw=%f\n", x
, y
, z
, rhw
);
3651 /* WARNING: The following things are taken from d3d7 and were not yet checked
3652 * against d3d8 or d3d9!
3655 /* Clipping conditions: From msdn
3657 * A vertex is clipped if it does not match the following requirements
3661 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3663 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3664 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3669 ( (-rhw
-eps
< x
) && (-rhw
-eps
< y
) && ( -eps
< z
) &&
3670 (x
<= rhw
+ eps
) && (y
<= rhw
+ eps
) && (z
<= rhw
+ eps
) &&
3673 /* "Normal" viewport transformation (not clipped)
3674 * 1) The values are divided by rhw
3675 * 2) The y axis is negative, so multiply it with -1
3676 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3677 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3678 * 4) Multiply x with Width/2 and add Width/2
3679 * 5) The same for the height
3680 * 6) Add the viewpoint X and Y to the 2D coordinates and
3681 * The minimum Z value to z
3682 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3684 * Well, basically it's simply a linear transformation into viewport
3696 z
*= vp
.MaxZ
- vp
.MinZ
;
3698 x
+= vp
.Width
/ 2 + vp
.X
;
3699 y
+= vp
.Height
/ 2 + vp
.Y
;
3704 /* That vertex got clipped
3705 * Contrary to OpenGL it is not dropped completely, it just
3706 * undergoes a different calculation.
3708 TRACE("Vertex got clipped\n");
3715 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3716 * outside of the main vertex buffer memory. That needs some more
3721 TRACE("Writing (%f %f %f) %f\n", x
, y
, z
, rhw
);
3724 ( (float *) dest_ptr
)[0] = x
;
3725 ( (float *) dest_ptr
)[1] = y
;
3726 ( (float *) dest_ptr
)[2] = z
;
3727 ( (float *) dest_ptr
)[3] = rhw
; /* SIC, see ddraw test! */
3729 dest_ptr
+= 3 * sizeof(float);
3731 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
3732 dest_ptr
+= sizeof(float);
3737 ( (float *) dest_conv
)[0] = x
* w
;
3738 ( (float *) dest_conv
)[1] = y
* w
;
3739 ( (float *) dest_conv
)[2] = z
* w
;
3740 ( (float *) dest_conv
)[3] = w
;
3742 dest_conv
+= 3 * sizeof(float);
3744 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
3745 dest_conv
+= sizeof(float);
3749 if (DestFVF
& WINED3DFVF_PSIZE
) {
3750 dest_ptr
+= sizeof(DWORD
);
3751 if(dest_conv
) dest_conv
+= sizeof(DWORD
);
3753 if (DestFVF
& WINED3DFVF_NORMAL
) {
3754 const struct wined3d_stream_info_element
*element
= &stream_info
->elements
[WINED3D_FFP_NORMAL
];
3755 const float *normal
= (const float *)(element
->data
+ i
* element
->stride
);
3756 /* AFAIK this should go into the lighting information */
3757 FIXME("Didn't expect the destination to have a normal\n");
3758 copy_and_next(dest_ptr
, normal
, 3 * sizeof(float));
3760 copy_and_next(dest_conv
, normal
, 3 * sizeof(float));
3764 if (DestFVF
& WINED3DFVF_DIFFUSE
) {
3765 const struct wined3d_stream_info_element
*element
= &stream_info
->elements
[WINED3D_FFP_DIFFUSE
];
3766 const DWORD
*color_d
= (const DWORD
*)(element
->data
+ i
* element
->stride
);
3767 if (!(stream_info
->use_map
& (1 << WINED3D_FFP_DIFFUSE
)))
3769 static BOOL warned
= FALSE
;
3772 ERR("No diffuse color in source, but destination has one\n");
3776 *( (DWORD
*) dest_ptr
) = 0xffffffff;
3777 dest_ptr
+= sizeof(DWORD
);
3780 *( (DWORD
*) dest_conv
) = 0xffffffff;
3781 dest_conv
+= sizeof(DWORD
);
3785 copy_and_next(dest_ptr
, color_d
, sizeof(DWORD
));
3787 *( (DWORD
*) dest_conv
) = (*color_d
& 0xff00ff00) ; /* Alpha + green */
3788 *( (DWORD
*) dest_conv
) |= (*color_d
& 0x00ff0000) >> 16; /* Red */
3789 *( (DWORD
*) dest_conv
) |= (*color_d
& 0xff0000ff) << 16; /* Blue */
3790 dest_conv
+= sizeof(DWORD
);
3795 if (DestFVF
& WINED3DFVF_SPECULAR
)
3797 /* What's the color value in the feedback buffer? */
3798 const struct wined3d_stream_info_element
*element
= &stream_info
->elements
[WINED3D_FFP_SPECULAR
];
3799 const DWORD
*color_s
= (const DWORD
*)(element
->data
+ i
* element
->stride
);
3800 if (!(stream_info
->use_map
& (1 << WINED3D_FFP_SPECULAR
)))
3802 static BOOL warned
= FALSE
;
3805 ERR("No specular color in source, but destination has one\n");
3809 *( (DWORD
*) dest_ptr
) = 0xFF000000;
3810 dest_ptr
+= sizeof(DWORD
);
3813 *( (DWORD
*) dest_conv
) = 0xFF000000;
3814 dest_conv
+= sizeof(DWORD
);
3818 copy_and_next(dest_ptr
, color_s
, sizeof(DWORD
));
3820 *( (DWORD
*) dest_conv
) = (*color_s
& 0xff00ff00) ; /* Alpha + green */
3821 *( (DWORD
*) dest_conv
) |= (*color_s
& 0x00ff0000) >> 16; /* Red */
3822 *( (DWORD
*) dest_conv
) |= (*color_s
& 0xff0000ff) << 16; /* Blue */
3823 dest_conv
+= sizeof(DWORD
);
3828 for (tex_index
= 0; tex_index
< numTextures
; tex_index
++) {
3829 const struct wined3d_stream_info_element
*element
= &stream_info
->elements
[WINED3D_FFP_TEXCOORD0
+ tex_index
];
3830 const float *tex_coord
= (const float *)(element
->data
+ i
* element
->stride
);
3831 if (!(stream_info
->use_map
& (1 << (WINED3D_FFP_TEXCOORD0
+ tex_index
))))
3833 ERR("No source texture, but destination requests one\n");
3834 dest_ptr
+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
3835 if(dest_conv
) dest_conv
+= GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
3838 copy_and_next(dest_ptr
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
3840 copy_and_next(dest_conv
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
3847 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, dest
->buffer_object
));
3848 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3849 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB
, dwDestIndex
* get_flexible_vertex_size(DestFVF
),
3850 dwCount
* get_flexible_vertex_size(DestFVF
),
3852 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3853 HeapFree(GetProcessHeap(), 0, dest_conv_addr
);
3860 #undef copy_and_next
3862 static HRESULT WINAPI
IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice
*iface
, UINT SrcStartIndex
, UINT DestIndex
,
3863 UINT VertexCount
, IWineD3DBuffer
*pDestBuffer
, IWineD3DVertexDeclaration
*pVertexDecl
, DWORD Flags
,
3866 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3867 struct wined3d_stream_info stream_info
;
3868 struct wined3d_context
*context
;
3869 BOOL vbo
= FALSE
, streamWasUP
= This
->stateBlock
->streamIsUP
;
3872 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This
, SrcStartIndex
, DestIndex
, VertexCount
, pDestBuffer
, pVertexDecl
, Flags
);
3875 ERR("Output vertex declaration not implemented yet\n");
3878 /* Need any context to write to the vbo. */
3879 context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
3881 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3882 * control the streamIsUP flag, thus restore it afterwards.
3884 This
->stateBlock
->streamIsUP
= FALSE
;
3885 device_stream_info_from_declaration(This
, FALSE
, &stream_info
, &vbo
);
3886 This
->stateBlock
->streamIsUP
= streamWasUP
;
3888 if(vbo
|| SrcStartIndex
) {
3890 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
3891 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
3893 * Also get the start index in, but only loop over all elements if there's something to add at all.
3895 for (i
= 0; i
< (sizeof(stream_info
.elements
) / sizeof(*stream_info
.elements
)); ++i
)
3897 struct wined3d_stream_info_element
*e
;
3899 if (!(stream_info
.use_map
& (1 << i
))) continue;
3901 e
= &stream_info
.elements
[i
];
3902 if (e
->buffer_object
)
3904 struct wined3d_buffer
*vb
= (struct wined3d_buffer
*)This
->stateBlock
->streamSource
[e
->stream_idx
];
3905 e
->buffer_object
= 0;
3906 e
->data
= (BYTE
*)((unsigned long)e
->data
+ (unsigned long)buffer_get_sysmem(vb
));
3908 GL_EXTCALL(glDeleteBuffersARB(1, &vb
->buffer_object
));
3909 vb
->buffer_object
= 0;
3912 if (e
->data
) e
->data
+= e
->stride
* SrcStartIndex
;
3916 hr
= process_vertices_strided(This
, DestIndex
, VertexCount
, &stream_info
,
3917 (struct wined3d_buffer
*)pDestBuffer
, Flags
, DestFVF
);
3919 context_release(context
);
3925 * Get / Set Texture Stage States
3926 * TODO: Verify against dx9 definitions
3928 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD Value
) {
3929 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3930 DWORD oldValue
= This
->updateStateBlock
->textureState
[Stage
][Type
];
3931 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
3933 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This
, Stage
, debug_d3dtexturestate(Type
), Type
, Value
);
3935 if (Stage
>= gl_info
->limits
.texture_stages
)
3937 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
3938 Stage
, gl_info
->limits
.texture_stages
- 1);
3942 This
->updateStateBlock
->changed
.textureState
[Stage
] |= 1 << Type
;
3943 This
->updateStateBlock
->textureState
[Stage
][Type
] = Value
;
3945 if (This
->isRecordingState
) {
3946 TRACE("Recording... not performing anything\n");
3950 /* Checked after the assignments to allow proper stateblock recording */
3951 if(oldValue
== Value
) {
3952 TRACE("App is setting the old value over, nothing to do\n");
3956 if(Stage
> This
->stateBlock
->lowest_disabled_stage
&&
3957 This
->StateTable
[STATE_TEXTURESTAGE(0, Type
)].representative
== STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP
)) {
3958 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3959 * Changes in other states are important on disabled stages too
3964 if(Type
== WINED3DTSS_COLOROP
) {
3967 if(Value
== WINED3DTOP_DISABLE
&& oldValue
!= WINED3DTOP_DISABLE
) {
3968 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3969 * they have to be disabled
3971 * The current stage is dirtified below.
3973 for(i
= Stage
+ 1; i
< This
->stateBlock
->lowest_disabled_stage
; i
++) {
3974 TRACE("Additionally dirtifying stage %u\n", i
);
3975 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
3977 This
->stateBlock
->lowest_disabled_stage
= Stage
;
3978 TRACE("New lowest disabled: %u\n", Stage
);
3979 } else if(Value
!= WINED3DTOP_DISABLE
&& oldValue
== WINED3DTOP_DISABLE
) {
3980 /* Previously disabled stage enabled. Stages above it may need enabling
3981 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3982 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3984 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3987 for (i
= Stage
+ 1; i
< This
->adapter
->gl_info
.limits
.texture_stages
; ++i
)
3989 if(This
->updateStateBlock
->textureState
[i
][WINED3DTSS_COLOROP
] == WINED3DTOP_DISABLE
) {
3992 TRACE("Additionally dirtifying stage %u due to enable\n", i
);
3993 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
3995 This
->stateBlock
->lowest_disabled_stage
= i
;
3996 TRACE("New lowest disabled: %u\n", i
);
4000 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, Type
));
4005 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD
* pValue
) {
4006 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4007 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This
, Stage
, Type
, This
->updateStateBlock
->textureState
[Stage
][Type
]);
4008 *pValue
= This
->updateStateBlock
->textureState
[Stage
][Type
];
4015 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTexture(IWineD3DDevice
*iface
,
4016 DWORD stage
, IWineD3DBaseTexture
*texture
)
4018 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4019 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
4020 IWineD3DBaseTexture
*prev
;
4022 TRACE("iface %p, stage %u, texture %p.\n", iface
, stage
, texture
);
4024 if (stage
>= WINED3DVERTEXTEXTURESAMPLER0
&& stage
<= WINED3DVERTEXTEXTURESAMPLER3
)
4025 stage
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
4027 /* Windows accepts overflowing this array... we do not. */
4028 if (stage
>= sizeof(This
->stateBlock
->textures
) / sizeof(*This
->stateBlock
->textures
))
4030 WARN("Ignoring invalid stage %u.\n", stage
);
4034 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4035 if (texture
&& ((IWineD3DTextureImpl
*)texture
)->resource
.pool
== WINED3DPOOL_SCRATCH
)
4037 WARN("Rejecting attempt to set scratch texture.\n");
4038 return WINED3DERR_INVALIDCALL
;
4041 This
->updateStateBlock
->changed
.textures
|= 1 << stage
;
4043 prev
= This
->updateStateBlock
->textures
[stage
];
4044 TRACE("Previous texture %p.\n", prev
);
4046 if (texture
== prev
)
4048 TRACE("App is setting the same texture again, nothing to do.\n");
4052 TRACE("Setting new texture to %p.\n", texture
);
4053 This
->updateStateBlock
->textures
[stage
] = texture
;
4055 if (This
->isRecordingState
)
4057 TRACE("Recording... not performing anything\n");
4059 if (texture
) IWineD3DBaseTexture_AddRef(texture
);
4060 if (prev
) IWineD3DBaseTexture_Release(prev
);
4067 IWineD3DBaseTextureImpl
*t
= (IWineD3DBaseTextureImpl
*)texture
;
4068 LONG bind_count
= InterlockedIncrement(&t
->baseTexture
.bindCount
);
4069 UINT dimensions
= IWineD3DBaseTexture_GetTextureDimensions(texture
);
4071 IWineD3DBaseTexture_AddRef(texture
);
4073 if (!prev
|| dimensions
!= IWineD3DBaseTexture_GetTextureDimensions(prev
))
4075 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADER
);
4078 if (!prev
&& stage
< gl_info
->limits
.texture_stages
)
4080 /* The source arguments for color and alpha ops have different
4081 * meanings when a NULL texture is bound, so the COLOROP and
4082 * ALPHAOP have to be dirtified. */
4083 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, WINED3DTSS_COLOROP
));
4084 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, WINED3DTSS_ALPHAOP
));
4087 if (bind_count
== 1) t
->baseTexture
.sampler
= stage
;
4092 IWineD3DBaseTextureImpl
*t
= (IWineD3DBaseTextureImpl
*)prev
;
4093 LONG bind_count
= InterlockedDecrement(&t
->baseTexture
.bindCount
);
4095 IWineD3DBaseTexture_Release(prev
);
4097 if (!texture
&& stage
< gl_info
->limits
.texture_stages
)
4099 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, WINED3DTSS_COLOROP
));
4100 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, WINED3DTSS_ALPHAOP
));
4103 if (bind_count
&& t
->baseTexture
.sampler
== stage
)
4107 /* Search for other stages the texture is bound to. Shouldn't
4108 * happen if applications bind textures to a single stage only. */
4109 TRACE("Searching for other stages the texture is bound to.\n");
4110 for (i
= 0; i
< MAX_COMBINED_SAMPLERS
; ++i
)
4112 if (This
->updateStateBlock
->textures
[i
] == prev
)
4114 TRACE("Texture is also bound to stage %u.\n", i
);
4115 t
->baseTexture
.sampler
= i
;
4122 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(stage
));
4127 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTexture(IWineD3DDevice
*iface
, DWORD Stage
, IWineD3DBaseTexture
** ppTexture
) {
4128 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4130 TRACE("(%p) : Stage %#x, ppTexture %p\n", This
, Stage
, ppTexture
);
4132 if (Stage
>= WINED3DVERTEXTEXTURESAMPLER0
&& Stage
<= WINED3DVERTEXTEXTURESAMPLER3
) {
4133 Stage
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
4136 if (Stage
>= sizeof(This
->stateBlock
->textures
)/sizeof(This
->stateBlock
->textures
[0])) {
4137 ERR("Current stage overflows textures array (stage %d)\n", Stage
);
4138 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
4141 *ppTexture
=This
->stateBlock
->textures
[Stage
];
4143 IWineD3DBaseTexture_AddRef(*ppTexture
);
4145 TRACE("(%p) : Returning %p\n", This
, *ppTexture
);
4153 static HRESULT WINAPI
IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice
*iface
, UINT swapchain_idx
,
4154 UINT backbuffer_idx
, WINED3DBACKBUFFER_TYPE backbuffer_type
, IWineD3DSurface
**backbuffer
)
4156 IWineD3DSwapChain
*swapchain
;
4159 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4160 iface
, swapchain_idx
, backbuffer_idx
, backbuffer_type
, backbuffer
);
4162 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, swapchain_idx
, &swapchain
);
4165 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx
, hr
);
4169 hr
= IWineD3DSwapChain_GetBackBuffer(swapchain
, backbuffer_idx
, backbuffer_type
, backbuffer
);
4170 IWineD3DSwapChain_Release(swapchain
);
4173 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx
, hr
);
4180 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice
*iface
, WINED3DCAPS
* pCaps
) {
4181 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4182 WARN("(%p) : stub, calling idirect3d for now\n", This
);
4183 return IWineD3D_GetDeviceCaps(This
->wined3d
, This
->adapter
->ordinal
, This
->devType
, pCaps
);
4186 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DDISPLAYMODE
* pMode
) {
4187 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4188 IWineD3DSwapChain
*swapChain
;
4191 if(iSwapChain
> 0) {
4192 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
4193 if (hr
== WINED3D_OK
) {
4194 hr
= IWineD3DSwapChain_GetDisplayMode(swapChain
, pMode
);
4195 IWineD3DSwapChain_Release(swapChain
);
4197 FIXME("(%p) Error getting display mode\n", This
);
4200 /* Don't read the real display mode,
4201 but return the stored mode instead. X11 can't change the color
4202 depth, and some apps are pretty angry if they SetDisplayMode from
4203 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4205 Also don't relay to the swapchain because with ddraw it's possible
4206 that there isn't a swapchain at all */
4207 pMode
->Width
= This
->ddraw_width
;
4208 pMode
->Height
= This
->ddraw_height
;
4209 pMode
->Format
= This
->ddraw_format
;
4210 pMode
->RefreshRate
= 0;
4218 * Stateblock related functions
4221 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice
*iface
) {
4222 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4223 IWineD3DStateBlock
*stateblock
;
4226 TRACE("(%p)\n", This
);
4228 if (This
->isRecordingState
) return WINED3DERR_INVALIDCALL
;
4230 hr
= IWineD3DDeviceImpl_CreateStateBlock(iface
, WINED3DSBT_RECORDED
, &stateblock
, NULL
);
4231 if (FAILED(hr
)) return hr
;
4233 IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
);
4234 This
->updateStateBlock
= (IWineD3DStateBlockImpl
*)stateblock
;
4235 This
->isRecordingState
= TRUE
;
4237 TRACE("(%p) recording stateblock %p\n", This
, stateblock
);
4242 static HRESULT WINAPI
IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice
*iface
, IWineD3DStateBlock
** ppStateBlock
) {
4243 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4244 IWineD3DStateBlockImpl
*object
= This
->updateStateBlock
;
4246 if (!This
->isRecordingState
) {
4247 WARN("(%p) not recording! returning error\n", This
);
4248 *ppStateBlock
= NULL
;
4249 return WINED3DERR_INVALIDCALL
;
4252 stateblock_init_contained_states(object
);
4254 *ppStateBlock
= (IWineD3DStateBlock
*) object
;
4255 This
->isRecordingState
= FALSE
;
4256 This
->updateStateBlock
= This
->stateBlock
;
4257 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
4258 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4259 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This
, *ppStateBlock
);
4264 * Scene related functions
4266 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginScene(IWineD3DDevice
*iface
) {
4267 /* At the moment we have no need for any functionality at the beginning
4269 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4270 TRACE("(%p)\n", This
);
4273 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4274 return WINED3DERR_INVALIDCALL
;
4276 This
->inScene
= TRUE
;
4280 static HRESULT WINAPI
IWineD3DDeviceImpl_EndScene(IWineD3DDevice
*iface
)
4282 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4283 struct wined3d_context
*context
;
4285 TRACE("(%p)\n", This
);
4287 if(!This
->inScene
) {
4288 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4289 return WINED3DERR_INVALIDCALL
;
4292 context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
4293 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4295 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4297 context_release(context
);
4299 This
->inScene
= FALSE
;
4303 static HRESULT WINAPI
IWineD3DDeviceImpl_Present(IWineD3DDevice
*iface
,
4304 const RECT
*pSourceRect
, const RECT
*pDestRect
,
4305 HWND hDestWindowOverride
, const RGNDATA
*pDirtyRegion
)
4307 IWineD3DSwapChain
*swapChain
= NULL
;
4309 int swapchains
= IWineD3DDeviceImpl_GetNumberOfSwapChains(iface
);
4311 TRACE("iface %p.\n", iface
);
4313 for(i
= 0 ; i
< swapchains
; i
++) {
4315 IWineD3DDeviceImpl_GetSwapChain(iface
, i
, &swapChain
);
4316 TRACE("presentinng chain %d, %p\n", i
, swapChain
);
4317 IWineD3DSwapChain_Present(swapChain
, pSourceRect
, pDestRect
, hDestWindowOverride
, pDirtyRegion
, 0);
4318 IWineD3DSwapChain_Release(swapChain
);
4324 static BOOL
is_full_clear(IWineD3DSurfaceImpl
*target
, const WINED3DVIEWPORT
*viewport
,
4325 const RECT
*scissor_rect
, const WINED3DRECT
*clear_rect
)
4327 /* partial viewport*/
4328 if (viewport
->X
!= 0 || viewport
->Y
!= 0
4329 || viewport
->Width
< target
->currentDesc
.Width
4330 || viewport
->Height
< target
->currentDesc
.Height
)
4333 /* partial scissor rect */
4334 if (scissor_rect
&& (scissor_rect
->left
> 0 || scissor_rect
->top
> 0
4335 || scissor_rect
->right
< target
->currentDesc
.Width
4336 || scissor_rect
->bottom
< target
->currentDesc
.Height
))
4339 /* partial clear rect */
4340 if (clear_rect
&& (clear_rect
->x1
> 0 || clear_rect
->y1
> 0
4341 || clear_rect
->x2
< target
->currentDesc
.Width
4342 || clear_rect
->y2
< target
->currentDesc
.Height
))
4348 /* Not called from the VTable (internal subroutine) */
4349 HRESULT
IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl
*This
, IWineD3DSurfaceImpl
*target
, DWORD Count
,
4350 const WINED3DRECT
*pRects
, DWORD Flags
, WINED3DCOLOR Color
, float Z
, DWORD Stencil
)
4352 IWineD3DStateBlockImpl
*stateblock
= This
->stateBlock
;
4353 const RECT
*scissor_rect
= stateblock
->renderState
[WINED3DRS_SCISSORTESTENABLE
] ? &stateblock
->scissorRect
: NULL
;
4354 const WINED3DRECT
*clear_rect
= (Count
> 0 && pRects
) ? pRects
: NULL
;
4355 const WINED3DVIEWPORT
*vp
= &stateblock
->viewport
;
4356 GLbitfield glMask
= 0;
4358 WINED3DRECT curRect
;
4360 UINT drawable_width
, drawable_height
;
4361 IWineD3DSurfaceImpl
*depth_stencil
= (IWineD3DSurfaceImpl
*) This
->stencilBufferTarget
;
4362 struct wined3d_context
*context
;
4364 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4365 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4366 * for the cleared parts, and the untouched parts.
4368 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4369 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4370 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4371 * checking all this if the dest surface is in the drawable anyway.
4373 if (Flags
& WINED3DCLEAR_TARGET
&& !(target
->Flags
& SFLAG_INDRAWABLE
))
4375 if (!is_full_clear(target
, vp
, scissor_rect
, clear_rect
))
4376 IWineD3DSurface_LoadLocation((IWineD3DSurface
*)target
, SFLAG_INDRAWABLE
, NULL
);
4379 context
= context_acquire(This
, (IWineD3DSurface
*)target
, CTXUSAGE_CLEAR
);
4380 if (!context
->valid
)
4382 context_release(context
);
4383 WARN("Invalid context, skipping clear.\n");
4387 target
->get_drawable_size(context
, &drawable_width
, &drawable_height
);
4391 /* Only set the values up once, as they are not changing */
4392 if (Flags
& WINED3DCLEAR_STENCIL
)
4394 if (context
->gl_info
->supported
[EXT_STENCIL_TWO_SIDE
])
4396 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT
);
4397 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE
));
4400 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_STENCILWRITEMASK
));
4401 glClearStencil(Stencil
);
4402 checkGLcall("glClearStencil");
4403 glMask
= glMask
| GL_STENCIL_BUFFER_BIT
;
4406 if (Flags
& WINED3DCLEAR_ZBUFFER
)
4408 DWORD location
= context
->render_offscreen
? SFLAG_DS_OFFSCREEN
: SFLAG_DS_ONSCREEN
;
4409 if (!(depth_stencil
->Flags
& location
) && !is_full_clear(depth_stencil
, vp
, scissor_rect
, clear_rect
))
4410 surface_load_ds_location(This
->stencilBufferTarget
, context
, location
);
4412 glDepthMask(GL_TRUE
);
4413 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ZWRITEENABLE
));
4415 checkGLcall("glClearDepth");
4416 glMask
= glMask
| GL_DEPTH_BUFFER_BIT
;
4419 if (Flags
& WINED3DCLEAR_TARGET
)
4421 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
4422 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE
));
4423 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1
));
4424 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2
));
4425 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3
));
4426 glClearColor(D3DCOLOR_R(Color
), D3DCOLOR_G(Color
), D3DCOLOR_B(Color
), D3DCOLOR_A(Color
));
4427 checkGLcall("glClearColor");
4428 glMask
= glMask
| GL_COLOR_BUFFER_BIT
;
4431 vp_rect
.left
= vp
->X
;
4432 vp_rect
.top
= vp
->Y
;
4433 vp_rect
.right
= vp
->X
+ vp
->Width
;
4434 vp_rect
.bottom
= vp
->Y
+ vp
->Height
;
4435 if (!(Count
> 0 && pRects
)) {
4436 if(This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
]) {
4437 IntersectRect(&vp_rect
, &vp_rect
, &This
->stateBlock
->scissorRect
);
4439 if (context
->render_offscreen
)
4441 glScissor(vp_rect
.left
, vp_rect
.top
,
4442 vp_rect
.right
- vp_rect
.left
, vp_rect
.bottom
- vp_rect
.top
);
4444 glScissor(vp_rect
.left
, drawable_height
- vp_rect
.bottom
,
4445 vp_rect
.right
- vp_rect
.left
, vp_rect
.bottom
- vp_rect
.top
);
4447 checkGLcall("glScissor");
4449 checkGLcall("glClear");
4451 /* Now process each rect in turn */
4452 for (i
= 0; i
< Count
; i
++) {
4453 /* Note gl uses lower left, width/height */
4454 IntersectRect((RECT
*)&curRect
, &vp_rect
, (const RECT
*)&pRects
[i
]);
4455 if(This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
]) {
4456 IntersectRect((RECT
*) &curRect
, (RECT
*) &curRect
, &This
->stateBlock
->scissorRect
);
4458 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This
,
4459 pRects
[i
].x1
, pRects
[i
].y1
, pRects
[i
].x2
, pRects
[i
].y2
,
4460 curRect
.x1
, (target
->currentDesc
.Height
- curRect
.y2
),
4461 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
4463 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4464 * The rectangle is not cleared, no error is returned, but further rectanlges are
4465 * still cleared if they are valid
4467 if(curRect
.x1
> curRect
.x2
|| curRect
.y1
> curRect
.y2
) {
4468 TRACE("Rectangle with negative dimensions, ignoring\n");
4472 if (context
->render_offscreen
)
4474 glScissor(curRect
.x1
, curRect
.y1
,
4475 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
4477 glScissor(curRect
.x1
, drawable_height
- curRect
.y2
,
4478 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
4480 checkGLcall("glScissor");
4483 checkGLcall("glClear");
4487 if (Flags
& WINED3DCLEAR_TARGET
)
4489 IWineD3DSurface_ModifyLocation((IWineD3DSurface
*)target
, SFLAG_INDRAWABLE
, TRUE
);
4491 if (Flags
& WINED3DCLEAR_ZBUFFER
) {
4492 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
4493 DWORD location
= context
->render_offscreen
? SFLAG_DS_OFFSCREEN
: SFLAG_DS_ONSCREEN
;
4494 surface_modify_ds_location(This
->stencilBufferTarget
, location
);
4499 wglFlush(); /* Flush to ensure ordering across contexts. */
4501 context_release(context
);
4506 static HRESULT WINAPI
IWineD3DDeviceImpl_Clear(IWineD3DDevice
*iface
, DWORD Count
, CONST WINED3DRECT
* pRects
,
4507 DWORD Flags
, WINED3DCOLOR Color
, float Z
, DWORD Stencil
) {
4508 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4509 IWineD3DSurfaceImpl
*target
= (IWineD3DSurfaceImpl
*)This
->render_targets
[0];
4511 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This
,
4512 Count
, pRects
, Flags
, Color
, Z
, Stencil
);
4514 if(Flags
& (WINED3DCLEAR_ZBUFFER
| WINED3DCLEAR_STENCIL
) && This
->stencilBufferTarget
== NULL
) {
4515 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4516 /* TODO: What about depth stencil buffers without stencil bits? */
4517 return WINED3DERR_INVALIDCALL
;
4520 return IWineD3DDeviceImpl_ClearSurface(This
, target
, Count
, pRects
, Flags
, Color
, Z
, Stencil
);
4527 static void WINAPI
IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice
*iface
,
4528 WINED3DPRIMITIVETYPE primitive_type
)
4530 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4532 TRACE("iface %p, primitive_type %s\n", iface
, debug_d3dprimitivetype(primitive_type
));
4534 This
->updateStateBlock
->changed
.primitive_type
= TRUE
;
4535 This
->updateStateBlock
->gl_primitive_type
= gl_primitive_type_from_d3d(primitive_type
);
4538 static void WINAPI
IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice
*iface
,
4539 WINED3DPRIMITIVETYPE
*primitive_type
)
4541 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4543 TRACE("iface %p, primitive_type %p\n", iface
, primitive_type
);
4545 *primitive_type
= d3d_primitive_type_from_gl(This
->stateBlock
->gl_primitive_type
);
4547 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type
));
4550 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice
*iface
, UINT StartVertex
, UINT vertex_count
)
4552 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4554 TRACE("(%p) : start %u, count %u\n", This
, StartVertex
, vertex_count
);
4556 if(!This
->stateBlock
->vertexDecl
) {
4557 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
4558 return WINED3DERR_INVALIDCALL
;
4561 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4562 if(This
->stateBlock
->streamIsUP
) {
4563 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
4564 This
->stateBlock
->streamIsUP
= FALSE
;
4567 if(This
->stateBlock
->loadBaseVertexIndex
!= 0) {
4568 This
->stateBlock
->loadBaseVertexIndex
= 0;
4569 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
4571 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4572 drawPrimitive(iface
, vertex_count
, StartVertex
/* start_idx */, 0 /* indxSize */, NULL
/* indxData */);
4576 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice
*iface
, UINT startIndex
, UINT index_count
)
4578 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4580 IWineD3DBuffer
*pIB
;
4583 pIB
= This
->stateBlock
->pIndexData
;
4585 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4586 * without an index buffer set. (The first time at least...)
4587 * D3D8 simply dies, but I doubt it can do much harm to return
4588 * D3DERR_INVALIDCALL there as well. */
4589 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This
);
4590 return WINED3DERR_INVALIDCALL
;
4593 if(!This
->stateBlock
->vertexDecl
) {
4594 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
4595 return WINED3DERR_INVALIDCALL
;
4598 if(This
->stateBlock
->streamIsUP
) {
4599 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
4600 This
->stateBlock
->streamIsUP
= FALSE
;
4602 vbo
= ((struct wined3d_buffer
*) pIB
)->buffer_object
;
4604 TRACE("(%p) : startIndex %u, index count %u.\n", This
, startIndex
, index_count
);
4606 if (This
->stateBlock
->IndexFmt
== WINED3DFMT_R16_UINT
) {
4612 if(This
->stateBlock
->loadBaseVertexIndex
!= This
->stateBlock
->baseVertexIndex
) {
4613 This
->stateBlock
->loadBaseVertexIndex
= This
->stateBlock
->baseVertexIndex
;
4614 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
4617 drawPrimitive(iface
, index_count
, startIndex
, idxStride
,
4618 vbo
? NULL
: ((struct wined3d_buffer
*)pIB
)->resource
.allocatedMemory
);
4623 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice
*iface
, UINT vertex_count
,
4624 const void *pVertexStreamZeroData
, UINT VertexStreamZeroStride
)
4626 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4629 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4630 This
, vertex_count
, pVertexStreamZeroData
, VertexStreamZeroStride
);
4632 if(!This
->stateBlock
->vertexDecl
) {
4633 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
4634 return WINED3DERR_INVALIDCALL
;
4637 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4638 vb
= This
->stateBlock
->streamSource
[0];
4639 This
->stateBlock
->streamSource
[0] = (IWineD3DBuffer
*)pVertexStreamZeroData
;
4640 if (vb
) IWineD3DBuffer_Release(vb
);
4641 This
->stateBlock
->streamOffset
[0] = 0;
4642 This
->stateBlock
->streamStride
[0] = VertexStreamZeroStride
;
4643 This
->stateBlock
->streamIsUP
= TRUE
;
4644 This
->stateBlock
->loadBaseVertexIndex
= 0;
4646 /* TODO: Only mark dirty if drawing from a different UP address */
4647 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
4649 drawPrimitive(iface
, vertex_count
, 0 /* start_idx */, 0 /* indxSize*/, NULL
/* indxData */);
4651 /* MSDN specifies stream zero settings must be set to NULL */
4652 This
->stateBlock
->streamStride
[0] = 0;
4653 This
->stateBlock
->streamSource
[0] = NULL
;
4655 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4656 * the new stream sources or use UP drawing again
4661 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice
*iface
,
4662 UINT index_count
, const void *pIndexData
, WINED3DFORMAT IndexDataFormat
,
4663 const void *pVertexStreamZeroData
, UINT VertexStreamZeroStride
)
4666 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4670 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4671 This
, index_count
, pIndexData
, IndexDataFormat
, pVertexStreamZeroData
, VertexStreamZeroStride
);
4673 if(!This
->stateBlock
->vertexDecl
) {
4674 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
4675 return WINED3DERR_INVALIDCALL
;
4678 if (IndexDataFormat
== WINED3DFMT_R16_UINT
) {
4684 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4685 vb
= This
->stateBlock
->streamSource
[0];
4686 This
->stateBlock
->streamSource
[0] = (IWineD3DBuffer
*)pVertexStreamZeroData
;
4687 if (vb
) IWineD3DBuffer_Release(vb
);
4688 This
->stateBlock
->streamIsUP
= TRUE
;
4689 This
->stateBlock
->streamOffset
[0] = 0;
4690 This
->stateBlock
->streamStride
[0] = VertexStreamZeroStride
;
4692 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4693 This
->stateBlock
->baseVertexIndex
= 0;
4694 This
->stateBlock
->loadBaseVertexIndex
= 0;
4695 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4696 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
4697 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
4699 drawPrimitive(iface
, index_count
, 0 /* start_idx */, idxStride
, pIndexData
);
4701 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4702 This
->stateBlock
->streamSource
[0] = NULL
;
4703 This
->stateBlock
->streamStride
[0] = 0;
4704 ib
= This
->stateBlock
->pIndexData
;
4706 IWineD3DBuffer_Release(ib
);
4707 This
->stateBlock
->pIndexData
= NULL
;
4709 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4710 * SetStreamSource to specify a vertex buffer
4716 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice
*iface
,
4717 UINT vertex_count
, const WineDirect3DVertexStridedData
*DrawPrimStrideData
)
4719 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
4721 /* Mark the state dirty until we have nicer tracking
4722 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4725 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
4726 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
4727 This
->stateBlock
->baseVertexIndex
= 0;
4728 This
->up_strided
= DrawPrimStrideData
;
4729 drawPrimitive(iface
, vertex_count
, 0, 0, NULL
);
4730 This
->up_strided
= NULL
;
4734 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice
*iface
,
4735 UINT vertex_count
, const WineDirect3DVertexStridedData
*DrawPrimStrideData
,
4736 UINT NumVertices
, const void *pIndexData
, WINED3DFORMAT IndexDataFormat
)
4738 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
4739 DWORD idxSize
= (IndexDataFormat
== WINED3DFMT_R32_UINT
? 4 : 2);
4741 /* Mark the state dirty until we have nicer tracking
4742 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4745 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
4746 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
4747 This
->stateBlock
->streamIsUP
= TRUE
;
4748 This
->stateBlock
->baseVertexIndex
= 0;
4749 This
->up_strided
= DrawPrimStrideData
;
4750 drawPrimitive(iface
, vertex_count
, 0 /* start_idx */, idxSize
, pIndexData
);
4751 This
->up_strided
= NULL
;
4755 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4756 static HRESULT
IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice
*iface
,
4757 IWineD3DVolume
*pSourceVolume
, IWineD3DVolume
*pDestinationVolume
)
4759 WINED3DLOCKED_BOX src
;
4760 WINED3DLOCKED_BOX dst
;
4763 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4764 iface
, pSourceVolume
, pDestinationVolume
);
4766 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4767 * dirtification to improve loading performance.
4769 hr
= IWineD3DVolume_LockBox(pSourceVolume
, &src
, NULL
, WINED3DLOCK_READONLY
);
4770 if(FAILED(hr
)) return hr
;
4771 hr
= IWineD3DVolume_LockBox(pDestinationVolume
, &dst
, NULL
, WINED3DLOCK_DISCARD
);
4773 IWineD3DVolume_UnlockBox(pSourceVolume
);
4777 memcpy(dst
.pBits
, src
.pBits
, ((IWineD3DVolumeImpl
*) pDestinationVolume
)->resource
.size
);
4779 hr
= IWineD3DVolume_UnlockBox(pDestinationVolume
);
4781 IWineD3DVolume_UnlockBox(pSourceVolume
);
4783 hr
= IWineD3DVolume_UnlockBox(pSourceVolume
);
4788 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice
*iface
,
4789 IWineD3DBaseTexture
*src_texture
, IWineD3DBaseTexture
*dst_texture
)
4791 unsigned int level_count
, i
;
4792 WINED3DRESOURCETYPE type
;
4795 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface
, src_texture
, dst_texture
);
4797 /* Verify that the source and destination textures are non-NULL. */
4798 if (!src_texture
|| !dst_texture
)
4800 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4801 return WINED3DERR_INVALIDCALL
;
4804 if (src_texture
== dst_texture
)
4806 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4807 return WINED3DERR_INVALIDCALL
;
4810 /* Verify that the source and destination textures are the same type. */
4811 type
= IWineD3DBaseTexture_GetType(src_texture
);
4812 if (IWineD3DBaseTexture_GetType(dst_texture
) != type
)
4814 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4815 return WINED3DERR_INVALIDCALL
;
4818 /* Check that both textures have the identical numbers of levels. */
4819 level_count
= IWineD3DBaseTexture_GetLevelCount(src_texture
);
4820 if (IWineD3DBaseTexture_GetLevelCount(dst_texture
) != level_count
)
4822 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4823 return WINED3DERR_INVALIDCALL
;
4826 /* Make sure that the destination texture is loaded. */
4827 ((IWineD3DBaseTextureImpl
*)dst_texture
)->baseTexture
.internal_preload(dst_texture
, SRGB_RGB
);
4829 /* Update every surface level of the texture. */
4832 case WINED3DRTYPE_TEXTURE
:
4834 IWineD3DSurface
*src_surface
;
4835 IWineD3DSurface
*dst_surface
;
4837 for (i
= 0; i
< level_count
; ++i
)
4839 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)src_texture
, i
, &src_surface
);
4840 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)dst_texture
, i
, &dst_surface
);
4841 hr
= IWineD3DDevice_UpdateSurface(iface
, src_surface
, NULL
, dst_surface
, NULL
);
4842 IWineD3DSurface_Release(dst_surface
);
4843 IWineD3DSurface_Release(src_surface
);
4846 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr
);
4853 case WINED3DRTYPE_CUBETEXTURE
:
4855 IWineD3DSurface
*src_surface
;
4856 IWineD3DSurface
*dst_surface
;
4857 WINED3DCUBEMAP_FACES face
;
4859 for (i
= 0; i
< level_count
; ++i
)
4861 /* Update each cube face. */
4862 for (face
= WINED3DCUBEMAP_FACE_POSITIVE_X
; face
<= WINED3DCUBEMAP_FACE_NEGATIVE_Z
; ++face
)
4864 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)src_texture
,
4865 face
, i
, &src_surface
);
4866 if (FAILED(hr
)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face
, i
, hr
);
4867 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)dst_texture
,
4868 face
, i
, &dst_surface
);
4869 if (FAILED(hr
)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face
, i
, hr
);
4870 hr
= IWineD3DDevice_UpdateSurface(iface
, src_surface
, NULL
, dst_surface
, NULL
);
4871 IWineD3DSurface_Release(dst_surface
);
4872 IWineD3DSurface_Release(src_surface
);
4875 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr
);
4883 case WINED3DRTYPE_VOLUMETEXTURE
:
4885 IWineD3DVolume
*src_volume
;
4886 IWineD3DVolume
*dst_volume
;
4888 for (i
= 0; i
< level_count
; ++i
)
4890 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture
*)src_texture
, i
, &src_volume
);
4891 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture
*)dst_texture
, i
, &dst_volume
);
4892 hr
= IWineD3DDeviceImpl_UpdateVolume(iface
, src_volume
, dst_volume
);
4893 IWineD3DVolume_Release(dst_volume
);
4894 IWineD3DVolume_Release(src_volume
);
4897 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr
);
4905 FIXME("Unsupported texture type %#x.\n", type
);
4906 return WINED3DERR_INVALIDCALL
;
4912 static HRESULT WINAPI
IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice
*iface
,UINT iSwapChain
, IWineD3DSurface
*pDestSurface
) {
4913 IWineD3DSwapChain
*swapChain
;
4915 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
4916 if(hr
== WINED3D_OK
) {
4917 hr
= IWineD3DSwapChain_GetFrontBufferData(swapChain
, pDestSurface
);
4918 IWineD3DSwapChain_Release(swapChain
);
4923 static HRESULT WINAPI
IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice
*iface
, DWORD
* pNumPasses
) {
4924 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4925 IWineD3DBaseTextureImpl
*texture
;
4928 TRACE("(%p) : %p\n", This
, pNumPasses
);
4930 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++) {
4931 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MINFILTER
] == WINED3DTEXF_NONE
) {
4932 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i
);
4933 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER
;
4935 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MAGFILTER
] == WINED3DTEXF_NONE
) {
4936 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i
);
4937 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER
;
4940 texture
= (IWineD3DBaseTextureImpl
*) This
->stateBlock
->textures
[i
];
4941 if (!texture
|| texture
->resource
.format_desc
->Flags
& WINED3DFMT_FLAG_FILTERING
) continue;
4943 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MAGFILTER
] != WINED3DTEXF_POINT
) {
4944 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i
);
4947 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MINFILTER
] != WINED3DTEXF_POINT
) {
4948 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i
);
4951 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MIPFILTER
] != WINED3DTEXF_NONE
&&
4952 This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MIPFILTER
] != WINED3DTEXF_POINT
/* sic! */) {
4953 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i
);
4958 /* return a sensible default */
4961 TRACE("returning D3D_OK\n");
4965 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl
*device
)
4969 for (i
= 0; i
< MAX_COMBINED_SAMPLERS
; ++i
)
4971 IWineD3DBaseTextureImpl
*texture
= (IWineD3DBaseTextureImpl
*)device
->stateBlock
->textures
[i
];
4972 if (texture
&& (texture
->resource
.format_desc
->format
== WINED3DFMT_P8_UINT
4973 || texture
->resource
.format_desc
->format
== WINED3DFMT_P8_UINT_A8_UNORM
))
4975 IWineD3DDeviceImpl_MarkStateDirty(device
, STATE_SAMPLER(i
));
4980 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, CONST PALETTEENTRY
* pEntries
) {
4981 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4984 PALETTEENTRY
**palettes
;
4986 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
4988 if (PaletteNumber
>= MAX_PALETTES
) {
4989 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This
, PaletteNumber
, MAX_PALETTES
);
4990 return WINED3DERR_INVALIDCALL
;
4993 if (PaletteNumber
>= This
->NumberOfPalettes
) {
4994 NewSize
= This
->NumberOfPalettes
;
4997 } while(PaletteNumber
>= NewSize
);
4998 palettes
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, This
->palettes
, sizeof(PALETTEENTRY
*) * NewSize
);
5000 ERR("Out of memory!\n");
5001 return E_OUTOFMEMORY
;
5003 This
->palettes
= palettes
;
5004 This
->NumberOfPalettes
= NewSize
;
5007 if (!This
->palettes
[PaletteNumber
]) {
5008 This
->palettes
[PaletteNumber
] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY
) * 256);
5009 if (!This
->palettes
[PaletteNumber
]) {
5010 ERR("Out of memory!\n");
5011 return E_OUTOFMEMORY
;
5015 for (j
= 0; j
< 256; ++j
) {
5016 This
->palettes
[PaletteNumber
][j
].peRed
= pEntries
[j
].peRed
;
5017 This
->palettes
[PaletteNumber
][j
].peGreen
= pEntries
[j
].peGreen
;
5018 This
->palettes
[PaletteNumber
][j
].peBlue
= pEntries
[j
].peBlue
;
5019 This
->palettes
[PaletteNumber
][j
].peFlags
= pEntries
[j
].peFlags
;
5021 if (PaletteNumber
== This
->currentPalette
) dirtify_p8_texture_samplers(This
);
5022 TRACE("(%p) : returning\n", This
);
5026 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, PALETTEENTRY
* pEntries
) {
5027 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5029 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5030 if (PaletteNumber
>= This
->NumberOfPalettes
|| !This
->palettes
[PaletteNumber
]) {
5031 /* What happens in such situation isn't documented; Native seems to silently abort
5032 on such conditions. Return Invalid Call. */
5033 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This
, PaletteNumber
, This
->NumberOfPalettes
);
5034 return WINED3DERR_INVALIDCALL
;
5036 for (j
= 0; j
< 256; ++j
) {
5037 pEntries
[j
].peRed
= This
->palettes
[PaletteNumber
][j
].peRed
;
5038 pEntries
[j
].peGreen
= This
->palettes
[PaletteNumber
][j
].peGreen
;
5039 pEntries
[j
].peBlue
= This
->palettes
[PaletteNumber
][j
].peBlue
;
5040 pEntries
[j
].peFlags
= This
->palettes
[PaletteNumber
][j
].peFlags
;
5042 TRACE("(%p) : returning\n", This
);
5046 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT PaletteNumber
) {
5047 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5048 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5049 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5050 (tested with reference rasterizer). Return Invalid Call. */
5051 if (PaletteNumber
>= This
->NumberOfPalettes
|| !This
->palettes
[PaletteNumber
]) {
5052 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This
, PaletteNumber
, This
->NumberOfPalettes
);
5053 return WINED3DERR_INVALIDCALL
;
5055 /*TODO: stateblocks */
5056 if (This
->currentPalette
!= PaletteNumber
) {
5057 This
->currentPalette
= PaletteNumber
;
5058 dirtify_p8_texture_samplers(This
);
5060 TRACE("(%p) : returning\n", This
);
5064 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT
* PaletteNumber
) {
5065 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5066 if (PaletteNumber
== NULL
) {
5067 WARN("(%p) : returning Invalid Call\n", This
);
5068 return WINED3DERR_INVALIDCALL
;
5070 /*TODO: stateblocks */
5071 *PaletteNumber
= This
->currentPalette
;
5072 TRACE("(%p) : returning %u\n", This
, *PaletteNumber
);
5076 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice
*iface
, BOOL bSoftware
) {
5077 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5081 FIXME("(%p) : stub\n", This
);
5085 This
->softwareVertexProcessing
= bSoftware
;
5090 static BOOL WINAPI
IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice
*iface
) {
5091 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5095 FIXME("(%p) : stub\n", This
);
5098 return This
->softwareVertexProcessing
;
5101 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice
*iface
,
5102 UINT swapchain_idx
, WINED3DRASTER_STATUS
*raster_status
)
5104 IWineD3DSwapChain
*swapchain
;
5107 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5108 iface
, swapchain_idx
, raster_status
);
5110 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, swapchain_idx
, &swapchain
);
5113 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx
, hr
);
5117 hr
= IWineD3DSwapChain_GetRasterStatus(swapchain
, raster_status
);
5118 IWineD3DSwapChain_Release(swapchain
);
5121 WARN("Failed to get raster status, hr %#x.\n", hr
);
5128 static HRESULT WINAPI
IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice
*iface
, float nSegments
)
5131 if(nSegments
!= 0.0f
) {
5134 FIXME("iface %p, nSegments %.8e stub!\n", iface
, nSegments
);
5141 static float WINAPI
IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice
*iface
)
5146 FIXME("iface %p stub!\n", iface
);
5152 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice
*iface
,
5153 IWineD3DSurface
*src_surface
, const RECT
*src_rect
,
5154 IWineD3DSurface
*dst_surface
, const POINT
*dst_point
)
5156 IWineD3DSurfaceImpl
*src_impl
= (IWineD3DSurfaceImpl
*)src_surface
;
5157 IWineD3DSurfaceImpl
*dst_impl
= (IWineD3DSurfaceImpl
*)dst_surface
;
5158 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5159 const struct wined3d_format_desc
*src_format
;
5160 const struct wined3d_format_desc
*dst_format
;
5161 struct wined3d_context
*context
;
5162 const unsigned char *data
;
5163 UINT update_w
, update_h
;
5164 CONVERT_TYPES convert
;
5168 struct wined3d_format_desc dummy_desc
;
5170 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s",
5171 iface
, src_surface
, wine_dbgstr_rect(src_rect
),
5172 dst_surface
, wine_dbgstr_point(dst_point
));
5174 if (src_impl
->resource
.pool
!= WINED3DPOOL_SYSTEMMEM
|| dst_impl
->resource
.pool
!= WINED3DPOOL_DEFAULT
)
5176 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5177 src_surface
, dst_surface
);
5178 return WINED3DERR_INVALIDCALL
;
5181 src_format
= src_impl
->resource
.format_desc
;
5182 dst_format
= dst_impl
->resource
.format_desc
;
5184 if (src_format
->format
!= dst_format
->format
)
5186 WARN("Source and destination surfaces should have the same format.\n");
5187 return WINED3DERR_INVALIDCALL
;
5190 dst_x
= dst_point
? dst_point
->x
: 0;
5191 dst_y
= dst_point
? dst_point
->y
: 0;
5193 /* This call loads the OpenGL surface directly, instead of copying the
5194 * surface to the destination's sysmem copy. If surface conversion is
5195 * needed, use BltFast instead to copy in sysmem and use regular surface
5197 d3dfmt_get_conv(dst_impl
, FALSE
, TRUE
, &dummy_desc
, &convert
);
5198 if (convert
!= NO_CONVERSION
)
5199 return IWineD3DSurface_BltFast(dst_surface
, dst_x
, dst_y
, src_surface
, src_rect
, 0);
5201 context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
5204 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
5205 checkGLcall("glActiveTextureARB");
5208 /* Make sure the surface is loaded and up to date */
5209 surface_internal_preload(dst_surface
, SRGB_RGB
);
5210 IWineD3DSurface_BindTexture(dst_surface
, FALSE
);
5212 src_w
= src_impl
->currentDesc
.Width
;
5213 src_h
= src_impl
->currentDesc
.Height
;
5214 update_w
= src_rect
? src_rect
->right
- src_rect
->left
: src_w
;
5215 update_h
= src_rect
? src_rect
->bottom
- src_rect
->top
: src_h
;
5217 data
= IWineD3DSurface_GetData(src_surface
);
5218 if (!data
) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5222 if (dst_format
->Flags
& WINED3DFMT_FLAG_COMPRESSED
)
5224 UINT row_length
= (update_w
/ src_format
->block_width
) * src_format
->block_byte_count
;
5225 UINT row_count
= update_h
/ src_format
->block_height
;
5226 UINT src_pitch
= IWineD3DSurface_GetPitch(src_surface
);
5230 data
+= (src_rect
->top
/ src_format
->block_height
) * src_pitch
;
5231 data
+= (src_rect
->left
/ src_format
->block_width
) * src_format
->block_byte_count
;
5234 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5235 "format %#x, image_size %#x, data %p.\n", dst_impl
->texture_target
, dst_impl
->texture_level
,
5236 dst_x
, dst_y
, update_w
, update_h
, dst_format
->glFormat
, row_count
* row_length
, data
);
5238 if (row_length
== src_pitch
)
5240 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl
->texture_target
, dst_impl
->texture_level
,
5241 dst_x
, dst_y
, update_w
, update_h
, dst_format
->glInternal
, row_count
* row_length
, data
));
5247 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5248 * can't use the unpack row length like below. */
5249 for (row
= 0, y
= dst_y
; row
< row_count
; ++row
)
5251 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl
->texture_target
, dst_impl
->texture_level
,
5252 dst_x
, y
, update_w
, src_format
->block_height
, dst_format
->glInternal
, row_length
, data
));
5253 y
+= src_format
->block_height
;
5257 checkGLcall("glCompressedTexSubImage2DARB");
5263 data
+= src_rect
->top
* src_w
* src_format
->byte_count
;
5264 data
+= src_rect
->left
* src_format
->byte_count
;
5267 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5268 dst_impl
->texture_target
, dst_impl
->texture_level
, dst_x
, dst_y
,
5269 update_w
, update_h
, dst_format
->glFormat
, dst_format
->glType
, data
);
5271 glPixelStorei(GL_UNPACK_ROW_LENGTH
, src_w
);
5272 glTexSubImage2D(dst_impl
->texture_target
, dst_impl
->texture_level
, dst_x
, dst_y
,
5273 update_w
, update_h
, dst_format
->glFormat
, dst_format
->glType
, data
);
5274 glPixelStorei(GL_UNPACK_ROW_LENGTH
, 0);
5275 checkGLcall("glTexSubImage2D");
5279 context_release(context
);
5281 IWineD3DSurface_ModifyLocation(dst_surface
, SFLAG_INTEXTURE
, TRUE
);
5282 sampler
= This
->rev_tex_unit_map
[0];
5283 if (sampler
!= WINED3D_UNMAPPED_STAGE
)
5285 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(sampler
));
5291 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice
*iface
, UINT Handle
, CONST
float* pNumSegs
, CONST WINED3DRECTPATCH_INFO
* pRectPatchInfo
) {
5292 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5293 struct WineD3DRectPatch
*patch
;
5294 GLenum old_primitive_type
;
5298 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This
, Handle
, pNumSegs
, pRectPatchInfo
);
5300 if(!(Handle
|| pRectPatchInfo
)) {
5301 /* TODO: Write a test for the return value, thus the FIXME */
5302 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5303 return WINED3DERR_INVALIDCALL
;
5307 i
= PATCHMAP_HASHFUNC(Handle
);
5309 LIST_FOR_EACH(e
, &This
->patches
[i
]) {
5310 patch
= LIST_ENTRY(e
, struct WineD3DRectPatch
, entry
);
5311 if(patch
->Handle
== Handle
) {
5318 TRACE("Patch does not exist. Creating a new one\n");
5319 patch
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*patch
));
5320 patch
->Handle
= Handle
;
5321 list_add_head(&This
->patches
[i
], &patch
->entry
);
5323 TRACE("Found existing patch %p\n", patch
);
5326 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5327 * attributes we have to tesselate, read back, and draw. This needs a patch
5328 * management structure instance. Create one.
5330 * A possible improvement is to check if a vertex shader is used, and if not directly
5333 FIXME("Drawing an uncached patch. This is slow\n");
5334 patch
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*patch
));
5337 if(pNumSegs
[0] != patch
->numSegs
[0] || pNumSegs
[1] != patch
->numSegs
[1] ||
5338 pNumSegs
[2] != patch
->numSegs
[2] || pNumSegs
[3] != patch
->numSegs
[3] ||
5339 (pRectPatchInfo
&& memcmp(pRectPatchInfo
, &patch
->RectPatchInfo
, sizeof(*pRectPatchInfo
)) != 0) ) {
5341 TRACE("Tesselation density or patch info changed, retesselating\n");
5343 if(pRectPatchInfo
) {
5344 patch
->RectPatchInfo
= *pRectPatchInfo
;
5346 patch
->numSegs
[0] = pNumSegs
[0];
5347 patch
->numSegs
[1] = pNumSegs
[1];
5348 patch
->numSegs
[2] = pNumSegs
[2];
5349 patch
->numSegs
[3] = pNumSegs
[3];
5351 hr
= tesselate_rectpatch(This
, patch
);
5353 WARN("Patch tesselation failed\n");
5355 /* Do not release the handle to store the params of the patch */
5357 HeapFree(GetProcessHeap(), 0, patch
);
5363 This
->currentPatch
= patch
;
5364 old_primitive_type
= This
->stateBlock
->gl_primitive_type
;
5365 This
->stateBlock
->gl_primitive_type
= GL_TRIANGLES
;
5366 IWineD3DDevice_DrawPrimitiveStrided(iface
, patch
->numSegs
[0] * patch
->numSegs
[1] * 2 * 3, &patch
->strided
);
5367 This
->stateBlock
->gl_primitive_type
= old_primitive_type
;
5368 This
->currentPatch
= NULL
;
5370 /* Destroy uncached patches */
5372 HeapFree(GetProcessHeap(), 0, patch
->mem
);
5373 HeapFree(GetProcessHeap(), 0, patch
);
5378 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice
*iface
,
5379 UINT handle
, const float *segment_count
, const WINED3DTRIPATCH_INFO
*patch_info
)
5381 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5382 iface
, handle
, segment_count
, patch_info
);
5387 static HRESULT WINAPI
IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice
*iface
, UINT Handle
) {
5388 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5390 struct WineD3DRectPatch
*patch
;
5392 TRACE("(%p) Handle(%d)\n", This
, Handle
);
5394 i
= PATCHMAP_HASHFUNC(Handle
);
5395 LIST_FOR_EACH(e
, &This
->patches
[i
]) {
5396 patch
= LIST_ENTRY(e
, struct WineD3DRectPatch
, entry
);
5397 if(patch
->Handle
== Handle
) {
5398 TRACE("Deleting patch %p\n", patch
);
5399 list_remove(&patch
->entry
);
5400 HeapFree(GetProcessHeap(), 0, patch
->mem
);
5401 HeapFree(GetProcessHeap(), 0, patch
);
5406 /* TODO: Write a test for the return value */
5407 FIXME("Attempt to destroy nonexistent patch\n");
5408 return WINED3DERR_INVALIDCALL
;
5411 static void color_fill_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*surface
,
5412 const WINED3DRECT
*rect
, const float color
[4])
5414 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5415 struct wined3d_context
*context
;
5417 if (rect
) IWineD3DSurface_LoadLocation(surface
, SFLAG_INDRAWABLE
, NULL
);
5418 IWineD3DSurface_ModifyLocation(surface
, SFLAG_INDRAWABLE
, TRUE
);
5420 if (!surface_is_offscreen(surface
))
5422 TRACE("Surface %p is onscreen\n", surface
);
5424 context
= context_acquire(This
, surface
, CTXUSAGE_RESOURCELOAD
);
5426 context_bind_fbo(context
, GL_FRAMEBUFFER
, NULL
);
5427 context_set_draw_buffer(context
, surface_get_gl_buffer(surface
));
5431 TRACE("Surface %p is offscreen\n", surface
);
5433 context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
5435 context_bind_fbo(context
, GL_FRAMEBUFFER
, &context
->dst_fbo
);
5436 context_attach_surface_fbo(context
, GL_FRAMEBUFFER
, 0, surface
);
5437 context_attach_depth_stencil_fbo(context
, GL_FRAMEBUFFER
, NULL
, FALSE
);
5441 glEnable(GL_SCISSOR_TEST
);
5442 if(surface_is_offscreen(surface
)) {
5443 glScissor(rect
->x1
, rect
->y1
, rect
->x2
- rect
->x1
, rect
->y2
- rect
->y1
);
5445 glScissor(rect
->x1
, ((IWineD3DSurfaceImpl
*)surface
)->currentDesc
.Height
- rect
->y2
,
5446 rect
->x2
- rect
->x1
, rect
->y2
- rect
->y1
);
5448 checkGLcall("glScissor");
5449 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SCISSORRECT
);
5451 glDisable(GL_SCISSOR_TEST
);
5453 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE
));
5455 glDisable(GL_BLEND
);
5456 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE
));
5458 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
5459 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE
));
5460 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1
));
5461 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2
));
5462 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3
));
5464 glClearColor(color
[0], color
[1], color
[2], color
[3]);
5465 glClear(GL_COLOR_BUFFER_BIT
);
5466 checkGLcall("glClear");
5470 wglFlush(); /* Flush to ensure ordering across contexts. */
5472 context_release(context
);
5475 static HRESULT WINAPI
IWineD3DDeviceImpl_ColorFill(IWineD3DDevice
*iface
,
5476 IWineD3DSurface
*pSurface
, const WINED3DRECT
*pRect
, WINED3DCOLOR color
)
5478 IWineD3DSurfaceImpl
*surface
= (IWineD3DSurfaceImpl
*) pSurface
;
5481 TRACE("iface %p, surface %p, rect %p, color 0x%08x.\n", iface
, pSurface
, pRect
, color
);
5483 if (surface
->resource
.pool
!= WINED3DPOOL_DEFAULT
&& surface
->resource
.pool
!= WINED3DPOOL_SYSTEMMEM
) {
5484 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5485 return WINED3DERR_INVALIDCALL
;
5488 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
5489 const float c
[4] = {D3DCOLOR_R(color
), D3DCOLOR_G(color
), D3DCOLOR_B(color
), D3DCOLOR_A(color
)};
5490 color_fill_fbo(iface
, pSurface
, pRect
, c
);
5493 /* Just forward this to the DirectDraw blitting engine */
5494 memset(&BltFx
, 0, sizeof(BltFx
));
5495 BltFx
.dwSize
= sizeof(BltFx
);
5496 BltFx
.u5
.dwFillColor
= color_convert_argb_to_fmt(color
, surface
->resource
.format_desc
->format
);
5497 return IWineD3DSurface_Blt(pSurface
, (const RECT
*)pRect
, NULL
, NULL
,
5498 WINEDDBLT_COLORFILL
, &BltFx
, WINED3DTEXF_POINT
);
5502 static void WINAPI
IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice
*iface
,
5503 IWineD3DRendertargetView
*rendertarget_view
, const float color
[4])
5505 IWineD3DResource
*resource
;
5506 IWineD3DSurface
*surface
;
5509 hr
= IWineD3DRendertargetView_GetResource(rendertarget_view
, &resource
);
5512 ERR("Failed to get resource, hr %#x\n", hr
);
5516 if (IWineD3DResource_GetType(resource
) != WINED3DRTYPE_SURFACE
)
5518 FIXME("Only supported on surface resources\n");
5519 IWineD3DResource_Release(resource
);
5523 surface
= (IWineD3DSurface
*)resource
;
5525 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
)
5527 color_fill_fbo(iface
, surface
, NULL
, color
);
5534 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5536 c
= ((DWORD
)(color
[2] * 255.0f
));
5537 c
|= ((DWORD
)(color
[1] * 255.0f
)) << 8;
5538 c
|= ((DWORD
)(color
[0] * 255.0f
)) << 16;
5539 c
|= ((DWORD
)(color
[3] * 255.0f
)) << 24;
5541 /* Just forward this to the DirectDraw blitting engine */
5542 memset(&BltFx
, 0, sizeof(BltFx
));
5543 BltFx
.dwSize
= sizeof(BltFx
);
5544 BltFx
.u5
.dwFillColor
= color_convert_argb_to_fmt(c
, ((IWineD3DSurfaceImpl
*)surface
)->resource
.format_desc
->format
);
5545 hr
= IWineD3DSurface_Blt(surface
, NULL
, NULL
, NULL
, WINEDDBLT_COLORFILL
, &BltFx
, WINED3DTEXF_POINT
);
5548 ERR("Blt failed, hr %#x\n", hr
);
5552 IWineD3DResource_Release(resource
);
5555 /* rendertarget and depth stencil functions */
5556 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice
* iface
,DWORD RenderTargetIndex
, IWineD3DSurface
**ppRenderTarget
) {
5557 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5559 if (RenderTargetIndex
>= This
->adapter
->gl_info
.limits
.buffers
)
5561 ERR("(%p) : Only %d render targets are supported.\n",
5562 This
, This
->adapter
->gl_info
.limits
.buffers
);
5563 return WINED3DERR_INVALIDCALL
;
5566 *ppRenderTarget
= This
->render_targets
[RenderTargetIndex
];
5567 TRACE("(%p) : RenderTarget %d Index returning %p\n", This
, RenderTargetIndex
, *ppRenderTarget
);
5568 /* Note inc ref on returned surface */
5569 if(*ppRenderTarget
!= NULL
)
5570 IWineD3DSurface_AddRef(*ppRenderTarget
);
5574 static HRESULT WINAPI
IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice
*iface
,
5575 IWineD3DSurface
*front
, IWineD3DSurface
*back
)
5577 IWineD3DSurfaceImpl
*front_impl
= (IWineD3DSurfaceImpl
*)front
;
5578 IWineD3DSurfaceImpl
*back_impl
= (IWineD3DSurfaceImpl
*)back
;
5579 IWineD3DSwapChainImpl
*swapchain
;
5582 TRACE("iface %p, front %p, back %p.\n", iface
, front
, back
);
5584 if (FAILED(hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**)&swapchain
)))
5586 ERR("Failed to get the swapchain, hr %#x.\n", hr
);
5590 if (front_impl
&& !(front_impl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
))
5592 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5593 IWineD3DSwapChain_Release((IWineD3DSwapChain
*)swapchain
);
5594 return WINED3DERR_INVALIDCALL
;
5599 if (!(back_impl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
))
5601 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5602 IWineD3DSwapChain_Release((IWineD3DSwapChain
*)swapchain
);
5603 return WINED3DERR_INVALIDCALL
;
5606 if (!swapchain
->backBuffer
)
5608 swapchain
->backBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*swapchain
->backBuffer
));
5609 if (!swapchain
->backBuffer
)
5611 ERR("Failed to allocate back buffer array memory.\n");
5612 IWineD3DSwapChain_Release((IWineD3DSwapChain
*)swapchain
);
5613 return E_OUTOFMEMORY
;
5618 if (swapchain
->frontBuffer
!= front
)
5620 TRACE("Changing the front buffer from %p to %p.\n", swapchain
->frontBuffer
, front
);
5622 if (swapchain
->frontBuffer
)
5624 IWineD3DSurface_SetContainer(swapchain
->frontBuffer
, NULL
);
5625 ((IWineD3DSurfaceImpl
*)swapchain
->frontBuffer
)->Flags
&= ~SFLAG_SWAPCHAIN
;
5627 swapchain
->frontBuffer
= front
;
5631 IWineD3DSurface_SetContainer(front
, (IWineD3DBase
*)swapchain
);
5632 front_impl
->Flags
|= SFLAG_SWAPCHAIN
;
5636 if (swapchain
->backBuffer
[0] != back
)
5638 TRACE("Changing the back buffer from %p to %p.\n", swapchain
->backBuffer
[0], back
);
5640 if (swapchain
->backBuffer
[0])
5642 IWineD3DSurface_SetContainer(swapchain
->backBuffer
[0], NULL
);
5643 ((IWineD3DSurfaceImpl
*)swapchain
->backBuffer
[0])->Flags
&= ~SFLAG_SWAPCHAIN
;
5645 swapchain
->backBuffer
[0] = back
;
5649 swapchain
->presentParms
.BackBufferWidth
= back_impl
->currentDesc
.Width
;
5650 swapchain
->presentParms
.BackBufferHeight
= back_impl
->currentDesc
.Height
;
5651 swapchain
->presentParms
.BackBufferFormat
= back_impl
->resource
.format_desc
->format
;
5652 swapchain
->presentParms
.BackBufferCount
= 1;
5654 IWineD3DSurface_SetContainer(back
, (IWineD3DBase
*)swapchain
);
5655 back_impl
->Flags
|= SFLAG_SWAPCHAIN
;
5659 swapchain
->presentParms
.BackBufferCount
= 0;
5660 HeapFree(GetProcessHeap(), 0, swapchain
->backBuffer
);
5661 swapchain
->backBuffer
= NULL
;
5665 IWineD3DSwapChain_Release((IWineD3DSwapChain
*)swapchain
);
5669 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice
* iface
, IWineD3DSurface
**ppZStencilSurface
) {
5670 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5671 *ppZStencilSurface
= This
->stencilBufferTarget
;
5672 TRACE("(%p) : zStencilSurface returning %p\n", This
, *ppZStencilSurface
);
5674 if(*ppZStencilSurface
!= NULL
) {
5675 /* Note inc ref on returned surface */
5676 IWineD3DSurface_AddRef(*ppZStencilSurface
);
5679 return WINED3DERR_NOTFOUND
;
5683 void stretch_rect_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*src_surface
, const RECT
*src_rect_in
,
5684 IWineD3DSurface
*dst_surface
, const RECT
*dst_rect_in
, const WINED3DTEXTUREFILTERTYPE filter
)
5686 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5687 GLbitfield mask
= GL_COLOR_BUFFER_BIT
; /* TODO: Support blitting depth/stencil surfaces */
5688 const struct wined3d_gl_info
*gl_info
;
5689 struct wined3d_context
*context
;
5691 POINT offset
= {0, 0};
5692 RECT src_rect
, dst_rect
;
5694 TRACE("(%p) : src_surface %p, src_rect_in %p, dst_surface %p, dst_rect_in %p, filter %s (0x%08x)\n",
5695 This
, src_surface
, src_rect_in
, dst_surface
, dst_rect_in
, debug_d3dtexturefiltertype(filter
), filter
);
5696 TRACE("src_rect_in %s\n", wine_dbgstr_rect(src_rect_in
));
5697 TRACE("dst_rect_in %s\n", wine_dbgstr_rect(dst_rect_in
));
5699 src_rect
= *src_rect_in
;
5700 dst_rect
= *dst_rect_in
;
5703 case WINED3DTEXF_LINEAR
:
5704 gl_filter
= GL_LINEAR
;
5708 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter
), filter
);
5709 case WINED3DTEXF_NONE
:
5710 case WINED3DTEXF_POINT
:
5711 gl_filter
= GL_NEAREST
;
5715 /* Make sure the drawables are up-to-date. Note that loading the
5716 * destination surface isn't strictly required if we overwrite the
5717 * entire surface. */
5718 IWineD3DSurface_LoadLocation(src_surface
, SFLAG_INDRAWABLE
, NULL
);
5719 IWineD3DSurface_LoadLocation(dst_surface
, SFLAG_INDRAWABLE
, NULL
);
5721 if (!surface_is_offscreen(src_surface
)) context
= context_acquire(This
, src_surface
, CTXUSAGE_RESOURCELOAD
);
5722 else if (!surface_is_offscreen(dst_surface
)) context
= context_acquire(This
, dst_surface
, CTXUSAGE_RESOURCELOAD
);
5723 else context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
5725 if (!context
->valid
)
5727 context_release(context
);
5728 WARN("Invalid context, skipping blit.\n");
5732 gl_info
= context
->gl_info
;
5734 if (!surface_is_offscreen(src_surface
))
5736 GLenum buffer
= surface_get_gl_buffer(src_surface
);
5738 TRACE("Source surface %p is onscreen\n", src_surface
);
5740 if(buffer
== GL_FRONT
) {
5743 ClientToScreen(context
->win_handle
, &offset
);
5744 GetClientRect(context
->win_handle
, &windowsize
);
5745 h
= windowsize
.bottom
- windowsize
.top
;
5746 src_rect
.left
-= offset
.x
; src_rect
.right
-=offset
.x
;
5747 src_rect
.top
= offset
.y
+ h
- src_rect
.top
;
5748 src_rect
.bottom
= offset
.y
+ h
- src_rect
.bottom
;
5750 src_rect
.top
= ((IWineD3DSurfaceImpl
*)src_surface
)->currentDesc
.Height
- src_rect
.top
;
5751 src_rect
.bottom
= ((IWineD3DSurfaceImpl
*)src_surface
)->currentDesc
.Height
- src_rect
.bottom
;
5755 context_bind_fbo(context
, GL_READ_FRAMEBUFFER
, NULL
);
5756 glReadBuffer(buffer
);
5757 checkGLcall("glReadBuffer()");
5759 TRACE("Source surface %p is offscreen\n", src_surface
);
5761 context_bind_fbo(context
, GL_READ_FRAMEBUFFER
, &context
->src_fbo
);
5762 context_attach_surface_fbo(context
, GL_READ_FRAMEBUFFER
, 0, src_surface
);
5763 glReadBuffer(GL_COLOR_ATTACHMENT0
);
5764 checkGLcall("glReadBuffer()");
5765 context_attach_depth_stencil_fbo(context
, GL_READ_FRAMEBUFFER
, NULL
, FALSE
);
5769 /* Attach dst surface to dst fbo */
5770 if (!surface_is_offscreen(dst_surface
))
5772 GLenum buffer
= surface_get_gl_buffer(dst_surface
);
5774 TRACE("Destination surface %p is onscreen\n", dst_surface
);
5776 if(buffer
== GL_FRONT
) {
5779 ClientToScreen(context
->win_handle
, &offset
);
5780 GetClientRect(context
->win_handle
, &windowsize
);
5781 h
= windowsize
.bottom
- windowsize
.top
;
5782 dst_rect
.left
-= offset
.x
; dst_rect
.right
-=offset
.x
;
5783 dst_rect
.top
= offset
.y
+ h
- dst_rect
.top
;
5784 dst_rect
.bottom
= offset
.y
+ h
- dst_rect
.bottom
;
5786 /* Screen coords = window coords, surface height = window height */
5787 dst_rect
.top
= ((IWineD3DSurfaceImpl
*)dst_surface
)->currentDesc
.Height
- dst_rect
.top
;
5788 dst_rect
.bottom
= ((IWineD3DSurfaceImpl
*)dst_surface
)->currentDesc
.Height
- dst_rect
.bottom
;
5792 context_bind_fbo(context
, GL_DRAW_FRAMEBUFFER
, NULL
);
5793 context_set_draw_buffer(context
, buffer
);
5797 TRACE("Destination surface %p is offscreen\n", dst_surface
);
5800 context_bind_fbo(context
, GL_DRAW_FRAMEBUFFER
, &context
->dst_fbo
);
5801 context_attach_surface_fbo(context
, GL_DRAW_FRAMEBUFFER
, 0, dst_surface
);
5802 context_set_draw_buffer(context
, GL_COLOR_ATTACHMENT0
);
5803 context_attach_depth_stencil_fbo(context
, GL_DRAW_FRAMEBUFFER
, NULL
, FALSE
);
5805 glDisable(GL_SCISSOR_TEST
);
5806 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE
));
5808 gl_info
->fbo_ops
.glBlitFramebuffer(src_rect
.left
, src_rect
.top
, src_rect
.right
, src_rect
.bottom
,
5809 dst_rect
.left
, dst_rect
.top
, dst_rect
.right
, dst_rect
.bottom
, mask
, gl_filter
);
5810 checkGLcall("glBlitFramebuffer()");
5814 wglFlush(); /* Flush to ensure ordering across contexts. */
5816 context_release(context
);
5818 IWineD3DSurface_ModifyLocation(dst_surface
, SFLAG_INDRAWABLE
, TRUE
);
5821 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice
*iface
, DWORD RenderTargetIndex
, IWineD3DSurface
*pRenderTarget
,
5822 BOOL set_viewport
) {
5823 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5825 TRACE("(%p) : Setting rendertarget %d to %p\n", This
, RenderTargetIndex
, pRenderTarget
);
5827 if (RenderTargetIndex
>= This
->adapter
->gl_info
.limits
.buffers
)
5829 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
5830 This
, RenderTargetIndex
, This
->adapter
->gl_info
.limits
.buffers
);
5831 return WINED3DERR_INVALIDCALL
;
5834 /* MSDN says that null disables the render target
5835 but a device must always be associated with a render target
5836 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5838 if (RenderTargetIndex
== 0 && pRenderTarget
== NULL
) {
5839 FIXME("Trying to set render target 0 to NULL\n");
5840 return WINED3DERR_INVALIDCALL
;
5842 if (pRenderTarget
&& !(((IWineD3DSurfaceImpl
*)pRenderTarget
)->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)) {
5843 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
);
5844 return WINED3DERR_INVALIDCALL
;
5847 /* If we are trying to set what we already have, don't bother */
5848 if (pRenderTarget
== This
->render_targets
[RenderTargetIndex
]) {
5849 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5852 if(pRenderTarget
) IWineD3DSurface_AddRef(pRenderTarget
);
5853 if(This
->render_targets
[RenderTargetIndex
]) IWineD3DSurface_Release(This
->render_targets
[RenderTargetIndex
]);
5854 This
->render_targets
[RenderTargetIndex
] = pRenderTarget
;
5856 /* Render target 0 is special */
5857 if(RenderTargetIndex
== 0 && set_viewport
) {
5858 /* Finally, reset the viewport and scissor rect as the MSDN states.
5859 * Tests show that stateblock recording is ignored, the change goes
5860 * directly into the primary stateblock.
5862 This
->stateBlock
->viewport
.Height
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Height
;
5863 This
->stateBlock
->viewport
.Width
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Width
;
5864 This
->stateBlock
->viewport
.X
= 0;
5865 This
->stateBlock
->viewport
.Y
= 0;
5866 This
->stateBlock
->viewport
.MaxZ
= 1.0f
;
5867 This
->stateBlock
->viewport
.MinZ
= 0.0f
;
5868 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VIEWPORT
);
5870 This
->stateBlock
->scissorRect
.top
= 0;
5871 This
->stateBlock
->scissorRect
.left
= 0;
5872 This
->stateBlock
->scissorRect
.right
= This
->stateBlock
->viewport
.Width
;
5873 This
->stateBlock
->scissorRect
.bottom
= This
->stateBlock
->viewport
.Height
;
5874 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SCISSORRECT
);
5879 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice
*iface
, IWineD3DSurface
*pNewZStencil
) {
5880 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5881 HRESULT hr
= WINED3D_OK
;
5882 IWineD3DSurface
*tmp
;
5884 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This
, This
->stencilBufferTarget
, pNewZStencil
);
5886 if (pNewZStencil
== This
->stencilBufferTarget
) {
5887 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5889 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
5890 * depending on the renter target implementation being used.
5891 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5892 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5893 * stencil buffer and incur an extra memory overhead
5894 ******************************************************/
5896 if (This
->stencilBufferTarget
) {
5897 if (((IWineD3DSwapChainImpl
*)This
->swapchains
[0])->presentParms
.Flags
& WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5898 || ((IWineD3DSurfaceImpl
*)This
->stencilBufferTarget
)->Flags
& SFLAG_DISCARD
) {
5899 surface_modify_ds_location(This
->stencilBufferTarget
, SFLAG_DS_DISCARDED
);
5901 struct wined3d_context
*context
= context_acquire(This
, This
->render_targets
[0], CTXUSAGE_RESOURCELOAD
);
5902 surface_load_ds_location(This
->stencilBufferTarget
, context
, SFLAG_DS_OFFSCREEN
);
5903 surface_modify_ds_location(This
->stencilBufferTarget
, SFLAG_DS_OFFSCREEN
);
5904 context_release(context
);
5908 tmp
= This
->stencilBufferTarget
;
5909 This
->stencilBufferTarget
= pNewZStencil
;
5910 /* should we be calling the parent or the wined3d surface? */
5911 if (NULL
!= This
->stencilBufferTarget
) IWineD3DSurface_AddRef(This
->stencilBufferTarget
);
5912 if (NULL
!= tmp
) IWineD3DSurface_Release(tmp
);
5915 if((!tmp
&& pNewZStencil
) || (!pNewZStencil
&& tmp
)) {
5916 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5917 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ZENABLE
));
5918 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_STENCILENABLE
));
5919 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_STENCILWRITEMASK
));
5926 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice
* iface
, UINT XHotSpot
,
5927 UINT YHotSpot
, IWineD3DSurface
*pCursorBitmap
) {
5928 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5929 /* TODO: the use of Impl is deprecated. */
5930 IWineD3DSurfaceImpl
* pSur
= (IWineD3DSurfaceImpl
*) pCursorBitmap
;
5931 WINED3DLOCKED_RECT lockedRect
;
5933 TRACE("(%p) : Spot Pos(%u,%u)\n", This
, XHotSpot
, YHotSpot
);
5935 /* some basic validation checks */
5936 if(This
->cursorTexture
) {
5937 struct wined3d_context
*context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
5939 glDeleteTextures(1, &This
->cursorTexture
);
5941 context_release(context
);
5942 This
->cursorTexture
= 0;
5945 if ( (pSur
->currentDesc
.Width
== 32) && (pSur
->currentDesc
.Height
== 32) )
5946 This
->haveHardwareCursor
= TRUE
;
5948 This
->haveHardwareCursor
= FALSE
;
5951 WINED3DLOCKED_RECT rect
;
5953 /* MSDN: Cursor must be A8R8G8B8 */
5954 if (pSur
->resource
.format_desc
->format
!= WINED3DFMT_B8G8R8A8_UNORM
)
5956 ERR("(%p) : surface(%p) has an invalid format\n", This
, pCursorBitmap
);
5957 return WINED3DERR_INVALIDCALL
;
5960 /* MSDN: Cursor must be smaller than the display mode */
5961 if(pSur
->currentDesc
.Width
> This
->ddraw_width
||
5962 pSur
->currentDesc
.Height
> This
->ddraw_height
) {
5963 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
);
5964 return WINED3DERR_INVALIDCALL
;
5967 if (!This
->haveHardwareCursor
) {
5968 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5970 /* Do not store the surface's pointer because the application may
5971 * release it after setting the cursor image. Windows doesn't
5972 * addref the set surface, so we can't do this either without
5973 * creating circular refcount dependencies. Copy out the gl texture
5976 This
->cursorWidth
= pSur
->currentDesc
.Width
;
5977 This
->cursorHeight
= pSur
->currentDesc
.Height
;
5978 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap
, &rect
, NULL
, WINED3DLOCK_READONLY
)))
5980 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
5981 const struct wined3d_format_desc
*format_desc
= getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM
, gl_info
);
5982 struct wined3d_context
*context
;
5983 char *mem
, *bits
= rect
.pBits
;
5984 GLint intfmt
= format_desc
->glInternal
;
5985 GLint format
= format_desc
->glFormat
;
5986 GLint type
= format_desc
->glType
;
5987 INT height
= This
->cursorHeight
;
5988 INT width
= This
->cursorWidth
;
5989 INT bpp
= format_desc
->byte_count
;
5993 /* Reformat the texture memory (pitch and width can be
5995 mem
= HeapAlloc(GetProcessHeap(), 0, width
* height
* bpp
);
5996 for(i
= 0; i
< height
; i
++)
5997 memcpy(&mem
[width
* bpp
* i
], &bits
[rect
.Pitch
* i
], width
* bpp
);
5998 IWineD3DSurface_UnlockRect(pCursorBitmap
);
6000 context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
6004 if (gl_info
->supported
[APPLE_CLIENT_STORAGE
])
6006 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
6007 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6010 /* Make sure that a proper texture unit is selected */
6011 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
6012 checkGLcall("glActiveTextureARB");
6013 sampler
= This
->rev_tex_unit_map
[0];
6014 if (sampler
!= WINED3D_UNMAPPED_STAGE
)
6016 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(sampler
));
6018 /* Create a new cursor texture */
6019 glGenTextures(1, &This
->cursorTexture
);
6020 checkGLcall("glGenTextures");
6021 glBindTexture(GL_TEXTURE_2D
, This
->cursorTexture
);
6022 checkGLcall("glBindTexture");
6023 /* Copy the bitmap memory into the cursor texture */
6024 glTexImage2D(GL_TEXTURE_2D
, 0, intfmt
, width
, height
, 0, format
, type
, mem
);
6025 HeapFree(GetProcessHeap(), 0, mem
);
6026 checkGLcall("glTexImage2D");
6028 if (gl_info
->supported
[APPLE_CLIENT_STORAGE
])
6030 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
6031 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6036 context_release(context
);
6040 FIXME("A cursor texture was not returned.\n");
6041 This
->cursorTexture
= 0;
6046 /* Draw a hardware cursor */
6047 ICONINFO cursorInfo
;
6049 /* Create and clear maskBits because it is not needed for
6050 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6052 DWORD
*maskBits
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
6053 (pSur
->currentDesc
.Width
* pSur
->currentDesc
.Height
/ 8));
6054 IWineD3DSurface_LockRect(pCursorBitmap
, &lockedRect
, NULL
,
6055 WINED3DLOCK_NO_DIRTY_UPDATE
|
6056 WINED3DLOCK_READONLY
6058 TRACE("width: %i height: %i\n", pSur
->currentDesc
.Width
,
6059 pSur
->currentDesc
.Height
);
6061 cursorInfo
.fIcon
= FALSE
;
6062 cursorInfo
.xHotspot
= XHotSpot
;
6063 cursorInfo
.yHotspot
= YHotSpot
;
6064 cursorInfo
.hbmMask
= CreateBitmap(pSur
->currentDesc
.Width
, pSur
->currentDesc
.Height
,
6066 cursorInfo
.hbmColor
= CreateBitmap(pSur
->currentDesc
.Width
, pSur
->currentDesc
.Height
,
6067 1, 32, lockedRect
.pBits
);
6068 IWineD3DSurface_UnlockRect(pCursorBitmap
);
6069 /* Create our cursor and clean up. */
6070 cursor
= CreateIconIndirect(&cursorInfo
);
6072 if (cursorInfo
.hbmMask
) DeleteObject(cursorInfo
.hbmMask
);
6073 if (cursorInfo
.hbmColor
) DeleteObject(cursorInfo
.hbmColor
);
6074 if (This
->hardwareCursor
) DestroyCursor(This
->hardwareCursor
);
6075 This
->hardwareCursor
= cursor
;
6076 HeapFree(GetProcessHeap(), 0, maskBits
);
6080 This
->xHotSpot
= XHotSpot
;
6081 This
->yHotSpot
= YHotSpot
;
6085 static void WINAPI
IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice
* iface
, int XScreenSpace
, int YScreenSpace
, DWORD Flags
) {
6086 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6087 TRACE("(%p) : SetPos to (%u,%u)\n", This
, XScreenSpace
, YScreenSpace
);
6089 This
->xScreenSpace
= XScreenSpace
;
6090 This
->yScreenSpace
= YScreenSpace
;
6096 static BOOL WINAPI
IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice
* iface
, BOOL bShow
) {
6097 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6098 BOOL oldVisible
= This
->bCursorVisible
;
6101 TRACE("(%p) : visible(%d)\n", This
, bShow
);
6104 * When ShowCursor is first called it should make the cursor appear at the OS's last
6105 * known cursor position. Because of this, some applications just repetitively call
6106 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6109 This
->xScreenSpace
= pt
.x
;
6110 This
->yScreenSpace
= pt
.y
;
6112 if (This
->haveHardwareCursor
) {
6113 This
->bCursorVisible
= bShow
;
6115 SetCursor(This
->hardwareCursor
);
6121 if (This
->cursorTexture
)
6122 This
->bCursorVisible
= bShow
;
6128 static HRESULT WINAPI
evict_managed_resource(IWineD3DResource
*resource
, void *data
) {
6129 TRACE("checking resource %p for eviction\n", resource
);
6130 if(((IWineD3DResourceImpl
*) resource
)->resource
.pool
== WINED3DPOOL_MANAGED
) {
6131 TRACE("Evicting %p\n", resource
);
6132 IWineD3DResource_UnLoad(resource
);
6134 IWineD3DResource_Release(resource
);
6138 static HRESULT WINAPI
IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice
*iface
)
6140 TRACE("iface %p.\n", iface
);
6142 IWineD3DDevice_EnumResources(iface
, evict_managed_resource
, NULL
);
6146 static HRESULT
updateSurfaceDesc(IWineD3DSurfaceImpl
*surface
, const WINED3DPRESENT_PARAMETERS
* pPresentationParameters
)
6148 IWineD3DDeviceImpl
*device
= surface
->resource
.device
;
6149 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
6151 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6152 if(surface
->Flags
& SFLAG_DIBSECTION
) {
6153 /* Release the DC */
6154 SelectObject(surface
->hDC
, surface
->dib
.holdbitmap
);
6155 DeleteDC(surface
->hDC
);
6156 /* Release the DIB section */
6157 DeleteObject(surface
->dib
.DIBsection
);
6158 surface
->dib
.bitmap_data
= NULL
;
6159 surface
->resource
.allocatedMemory
= NULL
;
6160 surface
->Flags
&= ~SFLAG_DIBSECTION
;
6162 surface
->currentDesc
.Width
= pPresentationParameters
->BackBufferWidth
;
6163 surface
->currentDesc
.Height
= pPresentationParameters
->BackBufferHeight
;
6164 if (gl_info
->supported
[ARB_TEXTURE_NON_POWER_OF_TWO
] || gl_info
->supported
[ARB_TEXTURE_RECTANGLE
]
6165 || gl_info
->supported
[WINE_NORMALIZED_TEXRECT
])
6167 surface
->pow2Width
= pPresentationParameters
->BackBufferWidth
;
6168 surface
->pow2Height
= pPresentationParameters
->BackBufferHeight
;
6170 surface
->pow2Width
= surface
->pow2Height
= 1;
6171 while (surface
->pow2Width
< pPresentationParameters
->BackBufferWidth
) surface
->pow2Width
<<= 1;
6172 while (surface
->pow2Height
< pPresentationParameters
->BackBufferHeight
) surface
->pow2Height
<<= 1;
6174 surface
->glRect
.left
= 0;
6175 surface
->glRect
.top
= 0;
6176 surface
->glRect
.right
= surface
->pow2Width
;
6177 surface
->glRect
.bottom
= surface
->pow2Height
;
6179 if (surface
->texture_name
)
6181 struct wined3d_context
*context
= context_acquire(device
, NULL
, CTXUSAGE_RESOURCELOAD
);
6183 glDeleteTextures(1, &surface
->texture_name
);
6185 context_release(context
);
6186 surface
->texture_name
= 0;
6187 surface
->Flags
&= ~SFLAG_CLIENT
;
6189 if(surface
->pow2Width
!= pPresentationParameters
->BackBufferWidth
||
6190 surface
->pow2Height
!= pPresentationParameters
->BackBufferHeight
) {
6191 surface
->Flags
|= SFLAG_NONPOW2
;
6193 surface
->Flags
&= ~SFLAG_NONPOW2
;
6195 HeapFree(GetProcessHeap(), 0, surface
->resource
.heapMemory
);
6196 surface
->resource
.allocatedMemory
= NULL
;
6197 surface
->resource
.heapMemory
= NULL
;
6198 surface
->resource
.size
= IWineD3DSurface_GetPitch((IWineD3DSurface
*) surface
) * surface
->pow2Width
;
6200 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6202 if(!surface_init_sysmem((IWineD3DSurface
*) surface
))
6204 return E_OUTOFMEMORY
;
6209 static HRESULT WINAPI
reset_unload_resources(IWineD3DResource
*resource
, void *data
) {
6210 TRACE("Unloading resource %p\n", resource
);
6211 IWineD3DResource_UnLoad(resource
);
6212 IWineD3DResource_Release(resource
);
6216 static BOOL
is_display_mode_supported(IWineD3DDeviceImpl
*This
, const WINED3DPRESENT_PARAMETERS
*pp
)
6219 WINED3DDISPLAYMODE m
;
6222 /* All Windowed modes are supported, as is leaving the current mode */
6223 if(pp
->Windowed
) return TRUE
;
6224 if(!pp
->BackBufferWidth
) return TRUE
;
6225 if(!pp
->BackBufferHeight
) return TRUE
;
6227 count
= IWineD3D_GetAdapterModeCount(This
->wined3d
, This
->adapter
->ordinal
, WINED3DFMT_UNKNOWN
);
6228 for(i
= 0; i
< count
; i
++) {
6229 memset(&m
, 0, sizeof(m
));
6230 hr
= IWineD3D_EnumAdapterModes(This
->wined3d
, This
->adapter
->ordinal
, WINED3DFMT_UNKNOWN
, i
, &m
);
6232 ERR("EnumAdapterModes failed\n");
6234 if(m
.Width
== pp
->BackBufferWidth
&& m
.Height
== pp
->BackBufferHeight
) {
6235 /* Mode found, it is supported */
6239 /* Mode not found -> not supported */
6243 static void delete_opengl_contexts(IWineD3DDevice
*iface
, IWineD3DSwapChainImpl
*swapchain
)
6245 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6246 const struct wined3d_gl_info
*gl_info
;
6247 struct wined3d_context
*context
;
6248 IWineD3DBaseShaderImpl
*shader
;
6250 context
= context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
6251 gl_info
= context
->gl_info
;
6253 IWineD3DDevice_EnumResources(iface
, reset_unload_resources
, NULL
);
6254 LIST_FOR_EACH_ENTRY(shader
, &This
->shaders
, IWineD3DBaseShaderImpl
, baseShader
.shader_list_entry
) {
6255 This
->shader_backend
->shader_destroy((IWineD3DBaseShader
*) shader
);
6259 if(This
->depth_blt_texture
) {
6260 glDeleteTextures(1, &This
->depth_blt_texture
);
6261 This
->depth_blt_texture
= 0;
6263 if (This
->depth_blt_rb
) {
6264 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &This
->depth_blt_rb
);
6265 This
->depth_blt_rb
= 0;
6266 This
->depth_blt_rb_w
= 0;
6267 This
->depth_blt_rb_h
= 0;
6271 This
->blitter
->free_private(iface
);
6272 This
->frag_pipe
->free_private(iface
);
6273 This
->shader_backend
->shader_free_private(iface
);
6274 destroy_dummy_textures(This
, gl_info
);
6276 context_release(context
);
6278 while (This
->numContexts
)
6280 context_destroy(This
, This
->contexts
[0]);
6282 HeapFree(GetProcessHeap(), 0, swapchain
->context
);
6283 swapchain
->context
= NULL
;
6284 swapchain
->num_contexts
= 0;
6287 static HRESULT
create_primary_opengl_context(IWineD3DDevice
*iface
, IWineD3DSwapChainImpl
*swapchain
)
6289 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6290 struct wined3d_context
*context
;
6292 IWineD3DSurfaceImpl
*target
;
6294 /* Recreate the primary swapchain's context */
6295 swapchain
->context
= HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain
->context
));
6296 if (!swapchain
->context
)
6298 ERR("Failed to allocate memory for swapchain context array.\n");
6299 return E_OUTOFMEMORY
;
6302 target
= (IWineD3DSurfaceImpl
*)(swapchain
->backBuffer
? swapchain
->backBuffer
[0] : swapchain
->frontBuffer
);
6303 if (!(context
= context_create(swapchain
, target
, swapchain
->ds_format
)))
6305 WARN("Failed to create context.\n");
6306 HeapFree(GetProcessHeap(), 0, swapchain
->context
);
6310 swapchain
->context
[0] = context
;
6311 swapchain
->num_contexts
= 1;
6312 create_dummy_textures(This
);
6313 context_release(context
);
6315 hr
= This
->shader_backend
->shader_alloc_private(iface
);
6318 ERR("Failed to allocate shader private data, hr %#x.\n", hr
);
6322 hr
= This
->frag_pipe
->alloc_private(iface
);
6325 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr
);
6326 This
->shader_backend
->shader_free_private(iface
);
6330 hr
= This
->blitter
->alloc_private(iface
);
6333 ERR("Failed to allocate blitter private data, hr %#x.\n", hr
);
6334 This
->frag_pipe
->free_private(iface
);
6335 This
->shader_backend
->shader_free_private(iface
);
6342 context_acquire(This
, NULL
, CTXUSAGE_RESOURCELOAD
);
6343 destroy_dummy_textures(This
, context
->gl_info
);
6344 context_release(context
);
6345 context_destroy(This
, context
);
6346 HeapFree(GetProcessHeap(), 0, swapchain
->context
);
6347 swapchain
->num_contexts
= 0;
6351 static HRESULT WINAPI
IWineD3DDeviceImpl_Reset(IWineD3DDevice
* iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
) {
6352 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6353 IWineD3DSwapChainImpl
*swapchain
;
6355 BOOL DisplayModeChanged
= FALSE
;
6356 WINED3DDISPLAYMODE mode
;
6357 TRACE("(%p)\n", This
);
6359 hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**) &swapchain
);
6361 ERR("Failed to get the first implicit swapchain\n");
6365 if(!is_display_mode_supported(This
, pPresentationParameters
)) {
6366 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6367 WARN("Requested mode: %d, %d\n", pPresentationParameters
->BackBufferWidth
,
6368 pPresentationParameters
->BackBufferHeight
);
6369 IWineD3DSwapChain_Release((IWineD3DSwapChain
*)swapchain
);
6370 return WINED3DERR_INVALIDCALL
;
6373 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6374 * on an existing gl context, so there's no real need for recreation.
6376 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6378 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6380 TRACE("New params:\n");
6381 TRACE("BackBufferWidth = %d\n", pPresentationParameters
->BackBufferWidth
);
6382 TRACE("BackBufferHeight = %d\n", pPresentationParameters
->BackBufferHeight
);
6383 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters
->BackBufferFormat
));
6384 TRACE("BackBufferCount = %d\n", pPresentationParameters
->BackBufferCount
);
6385 TRACE("MultiSampleType = %d\n", pPresentationParameters
->MultiSampleType
);
6386 TRACE("MultiSampleQuality = %d\n", pPresentationParameters
->MultiSampleQuality
);
6387 TRACE("SwapEffect = %d\n", pPresentationParameters
->SwapEffect
);
6388 TRACE("hDeviceWindow = %p\n", pPresentationParameters
->hDeviceWindow
);
6389 TRACE("Windowed = %s\n", pPresentationParameters
->Windowed
? "true" : "false");
6390 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters
->EnableAutoDepthStencil
? "true" : "false");
6391 TRACE("Flags = %08x\n", pPresentationParameters
->Flags
);
6392 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters
->FullScreen_RefreshRateInHz
);
6393 TRACE("PresentationInterval = %d\n", pPresentationParameters
->PresentationInterval
);
6395 /* No special treatment of these parameters. Just store them */
6396 swapchain
->presentParms
.SwapEffect
= pPresentationParameters
->SwapEffect
;
6397 swapchain
->presentParms
.Flags
= pPresentationParameters
->Flags
;
6398 swapchain
->presentParms
.PresentationInterval
= pPresentationParameters
->PresentationInterval
;
6399 swapchain
->presentParms
.FullScreen_RefreshRateInHz
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
6401 /* What to do about these? */
6402 if(pPresentationParameters
->BackBufferCount
!= 0 &&
6403 pPresentationParameters
->BackBufferCount
!= swapchain
->presentParms
.BackBufferCount
) {
6404 ERR("Cannot change the back buffer count yet\n");
6406 if(pPresentationParameters
->BackBufferFormat
!= WINED3DFMT_UNKNOWN
&&
6407 pPresentationParameters
->BackBufferFormat
!= swapchain
->presentParms
.BackBufferFormat
) {
6408 ERR("Cannot change the back buffer format yet\n");
6410 if(pPresentationParameters
->hDeviceWindow
!= NULL
&&
6411 pPresentationParameters
->hDeviceWindow
!= swapchain
->presentParms
.hDeviceWindow
) {
6412 ERR("Cannot change the device window yet\n");
6414 if (pPresentationParameters
->EnableAutoDepthStencil
&& !This
->auto_depth_stencil_buffer
) {
6417 TRACE("Creating the depth stencil buffer\n");
6419 hrc
= IWineD3DDeviceParent_CreateDepthStencilSurface(This
->device_parent
,
6421 pPresentationParameters
->BackBufferWidth
,
6422 pPresentationParameters
->BackBufferHeight
,
6423 pPresentationParameters
->AutoDepthStencilFormat
,
6424 pPresentationParameters
->MultiSampleType
,
6425 pPresentationParameters
->MultiSampleQuality
,
6427 &This
->auto_depth_stencil_buffer
);
6430 ERR("Failed to create the depth stencil buffer\n");
6431 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
6432 return WINED3DERR_INVALIDCALL
;
6436 /* Reset the depth stencil */
6437 if (pPresentationParameters
->EnableAutoDepthStencil
)
6438 IWineD3DDevice_SetDepthStencilSurface(iface
, This
->auto_depth_stencil_buffer
);
6440 IWineD3DDevice_SetDepthStencilSurface(iface
, NULL
);
6442 TRACE("Resetting stateblock\n");
6443 IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
);
6444 IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->stateBlock
);
6446 delete_opengl_contexts(iface
, swapchain
);
6448 if(pPresentationParameters
->Windowed
) {
6449 mode
.Width
= swapchain
->orig_width
;
6450 mode
.Height
= swapchain
->orig_height
;
6451 mode
.RefreshRate
= 0;
6452 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
6454 mode
.Width
= pPresentationParameters
->BackBufferWidth
;
6455 mode
.Height
= pPresentationParameters
->BackBufferHeight
;
6456 mode
.RefreshRate
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
6457 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
6460 /* Should Width == 800 && Height == 0 set 800x600? */
6461 if(pPresentationParameters
->BackBufferWidth
!= 0 && pPresentationParameters
->BackBufferHeight
!= 0 &&
6462 (pPresentationParameters
->BackBufferWidth
!= swapchain
->presentParms
.BackBufferWidth
||
6463 pPresentationParameters
->BackBufferHeight
!= swapchain
->presentParms
.BackBufferHeight
))
6467 if(!pPresentationParameters
->Windowed
) {
6468 DisplayModeChanged
= TRUE
;
6470 swapchain
->presentParms
.BackBufferWidth
= pPresentationParameters
->BackBufferWidth
;
6471 swapchain
->presentParms
.BackBufferHeight
= pPresentationParameters
->BackBufferHeight
;
6473 hr
= updateSurfaceDesc((IWineD3DSurfaceImpl
*)swapchain
->frontBuffer
, pPresentationParameters
);
6476 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
6480 for(i
= 0; i
< swapchain
->presentParms
.BackBufferCount
; i
++) {
6481 hr
= updateSurfaceDesc((IWineD3DSurfaceImpl
*)swapchain
->backBuffer
[i
], pPresentationParameters
);
6484 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
6488 if(This
->auto_depth_stencil_buffer
) {
6489 hr
= updateSurfaceDesc((IWineD3DSurfaceImpl
*)This
->auto_depth_stencil_buffer
, pPresentationParameters
);
6492 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
6498 if (!pPresentationParameters
->Windowed
!= !swapchain
->presentParms
.Windowed
6499 || DisplayModeChanged
)
6501 IWineD3DDevice_SetDisplayMode(iface
, 0, &mode
);
6503 if (!pPresentationParameters
->Windowed
)
6505 if(swapchain
->presentParms
.Windowed
) {
6506 /* switch from windowed to fs */
6507 swapchain_setup_fullscreen_window(swapchain
, pPresentationParameters
->BackBufferWidth
,
6508 pPresentationParameters
->BackBufferHeight
);
6510 /* Fullscreen -> fullscreen mode change */
6511 MoveWindow(swapchain
->device_window
, 0, 0,
6512 pPresentationParameters
->BackBufferWidth
, pPresentationParameters
->BackBufferHeight
,
6516 else if (!swapchain
->presentParms
.Windowed
)
6518 /* Fullscreen -> windowed switch */
6519 swapchain_restore_fullscreen_window(swapchain
);
6521 swapchain
->presentParms
.Windowed
= pPresentationParameters
->Windowed
;
6522 } else if(!pPresentationParameters
->Windowed
) {
6523 DWORD style
= This
->style
, exStyle
= This
->exStyle
;
6524 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6525 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6526 * Reset to clear up their mess. Guild Wars also loses the device during that.
6530 swapchain_setup_fullscreen_window(swapchain
, pPresentationParameters
->BackBufferWidth
,
6531 pPresentationParameters
->BackBufferHeight
);
6532 This
->style
= style
;
6533 This
->exStyle
= exStyle
;
6536 /* Note: No parent needed for initial internal stateblock */
6537 hr
= IWineD3DDevice_CreateStateBlock(iface
, WINED3DSBT_INIT
, (IWineD3DStateBlock
**)&This
->stateBlock
, NULL
);
6538 if (FAILED(hr
)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr
);
6539 else TRACE("Created stateblock %p\n", This
->stateBlock
);
6540 This
->updateStateBlock
= This
->stateBlock
;
6541 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
6543 hr
= IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock
*) This
->stateBlock
);
6545 ERR("Resetting the stateblock failed with error 0x%08x\n", hr
);
6548 if(wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
)
6551 GetClientRect(swapchain
->win_handle
, &client_rect
);
6553 if(!swapchain
->presentParms
.BackBufferCount
)
6555 TRACE("Single buffered rendering\n");
6556 swapchain
->render_to_fbo
= FALSE
;
6558 else if(swapchain
->presentParms
.BackBufferWidth
!= client_rect
.right
||
6559 swapchain
->presentParms
.BackBufferHeight
!= client_rect
.bottom
)
6561 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6562 swapchain
->presentParms
.BackBufferWidth
,
6563 swapchain
->presentParms
.BackBufferHeight
,
6564 client_rect
.right
, client_rect
.bottom
);
6565 swapchain
->render_to_fbo
= TRUE
;
6569 TRACE("Rendering directly to GL_BACK\n");
6570 swapchain
->render_to_fbo
= FALSE
;
6574 hr
= create_primary_opengl_context(iface
, swapchain
);
6575 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
6577 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6583 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice
*iface
, BOOL enable_dialogs
)
6585 TRACE("iface %p, enable_dialogs %#x.\n", iface
, enable_dialogs
);
6587 if (!enable_dialogs
) FIXME("Dialogs cannot be disabled yet.\n");
6593 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice
*iface
, WINED3DDEVICE_CREATION_PARAMETERS
*pParameters
) {
6594 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6595 TRACE("(%p) : pParameters %p\n", This
, pParameters
);
6597 *pParameters
= This
->createParms
;
6601 static void WINAPI
IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice
* iface
, UINT iSwapChain
, DWORD Flags
, CONST WINED3DGAMMARAMP
* pRamp
) {
6602 IWineD3DSwapChain
*swapchain
;
6604 TRACE("Relaying to swapchain\n");
6606 if (IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
) == WINED3D_OK
) {
6607 IWineD3DSwapChain_SetGammaRamp(swapchain
, Flags
, pRamp
);
6608 IWineD3DSwapChain_Release(swapchain
);
6612 static void WINAPI
IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DGAMMARAMP
* pRamp
) {
6613 IWineD3DSwapChain
*swapchain
;
6615 TRACE("Relaying to swapchain\n");
6617 if (IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
) == WINED3D_OK
) {
6618 IWineD3DSwapChain_GetGammaRamp(swapchain
, pRamp
);
6619 IWineD3DSwapChain_Release(swapchain
);
6624 /** ********************************************************
6625 * Notification functions
6626 ** ********************************************************/
6627 /** This function must be called in the release of a resource when ref == 0,
6628 * the contents of resource must still be correct,
6629 * any handles to other resource held by the caller must be closed
6630 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6631 *****************************************************/
6632 void device_resource_add(IWineD3DDeviceImpl
*This
, IWineD3DResource
*resource
)
6634 TRACE("(%p) : Adding resource %p\n", This
, resource
);
6636 list_add_head(&This
->resources
, &((IWineD3DResourceImpl
*) resource
)->resource
.resource_list_entry
);
6639 static void device_resource_remove(IWineD3DDeviceImpl
*This
, IWineD3DResource
*resource
)
6641 TRACE("(%p) : Removing resource %p\n", This
, resource
);
6643 list_remove(&((IWineD3DResourceImpl
*) resource
)->resource
.resource_list_entry
);
6646 void device_resource_released(IWineD3DDeviceImpl
*This
, IWineD3DResource
*resource
)
6648 WINED3DRESOURCETYPE type
= IWineD3DResource_GetType(resource
);
6651 TRACE("(%p) : resource %p\n", This
, resource
);
6653 context_resource_released((IWineD3DDevice
*)This
, resource
, type
);
6656 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6657 case WINED3DRTYPE_SURFACE
: {
6660 if (This
->d3d_initialized
)
6662 for (i
= 0; i
< This
->adapter
->gl_info
.limits
.buffers
; ++i
)
6664 if (This
->render_targets
[i
] == (IWineD3DSurface
*)resource
) {
6665 This
->render_targets
[i
] = NULL
;
6668 if (This
->stencilBufferTarget
== (IWineD3DSurface
*)resource
) {
6669 This
->stencilBufferTarget
= NULL
;
6675 case WINED3DRTYPE_TEXTURE
:
6676 case WINED3DRTYPE_CUBETEXTURE
:
6677 case WINED3DRTYPE_VOLUMETEXTURE
:
6678 for (counter
= 0; counter
< MAX_COMBINED_SAMPLERS
; counter
++) {
6679 if (This
->stateBlock
!= NULL
&& This
->stateBlock
->textures
[counter
] == (IWineD3DBaseTexture
*)resource
) {
6680 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter
, resource
);
6681 This
->stateBlock
->textures
[counter
] = NULL
;
6683 if (This
->updateStateBlock
!= This
->stateBlock
){
6684 if (This
->updateStateBlock
->textures
[counter
] == (IWineD3DBaseTexture
*)resource
) {
6685 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter
, resource
);
6686 This
->updateStateBlock
->textures
[counter
] = NULL
;
6691 case WINED3DRTYPE_VOLUME
:
6692 /* TODO: nothing really? */
6694 case WINED3DRTYPE_BUFFER
:
6697 TRACE("Cleaning up stream pointers\n");
6699 for(streamNumber
= 0; streamNumber
< MAX_STREAMS
; streamNumber
++){
6700 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6701 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6703 if (This
->updateStateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
6704 if ((IWineD3DResource
*)This
->updateStateBlock
->streamSource
[streamNumber
] == resource
) {
6705 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber
);
6706 This
->updateStateBlock
->streamSource
[streamNumber
] = 0;
6707 /* Set changed flag? */
6710 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) */
6711 if ((IWineD3DResource
*)This
->stateBlock
->streamSource
[streamNumber
] == resource
) {
6712 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber
);
6713 This
->stateBlock
->streamSource
[streamNumber
] = 0;
6718 if (This
->updateStateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
6719 if (This
->updateStateBlock
->pIndexData
== (IWineD3DBuffer
*)resource
) {
6720 This
->updateStateBlock
->pIndexData
= NULL
;
6723 if (This
->stateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
6724 if (This
->stateBlock
->pIndexData
== (IWineD3DBuffer
*)resource
) {
6725 This
->stateBlock
->pIndexData
= NULL
;
6732 FIXME("(%p) unknown resource type %p %u\n", This
, resource
, IWineD3DResource_GetType(resource
));
6737 /* Remove the resource from the resourceStore */
6738 device_resource_remove(This
, resource
);
6740 TRACE("Resource released\n");
6744 static HRESULT WINAPI
IWineD3DDeviceImpl_EnumResources(IWineD3DDevice
*iface
, D3DCB_ENUMRESOURCES pCallback
, void *pData
) {
6745 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6746 IWineD3DResourceImpl
*resource
, *cursor
;
6748 TRACE("(%p)->(%p,%p)\n", This
, pCallback
, pData
);
6750 LIST_FOR_EACH_ENTRY_SAFE(resource
, cursor
, &This
->resources
, IWineD3DResourceImpl
, resource
.resource_list_entry
) {
6751 TRACE("enumerating resource %p\n", resource
);
6752 IWineD3DResource_AddRef((IWineD3DResource
*) resource
);
6753 ret
= pCallback((IWineD3DResource
*) resource
, pData
);
6754 if(ret
== S_FALSE
) {
6755 TRACE("Canceling enumeration\n");
6762 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice
*iface
, HDC dc
, IWineD3DSurface
**surface
)
6764 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6765 IWineD3DResourceImpl
*resource
;
6767 LIST_FOR_EACH_ENTRY(resource
, &This
->resources
, IWineD3DResourceImpl
, resource
.resource_list_entry
)
6769 WINED3DRESOURCETYPE type
= IWineD3DResource_GetType((IWineD3DResource
*)resource
);
6770 if (type
== WINED3DRTYPE_SURFACE
)
6772 if (((IWineD3DSurfaceImpl
*)resource
)->hDC
== dc
)
6774 TRACE("Found surface %p for dc %p.\n", resource
, dc
);
6775 *surface
= (IWineD3DSurface
*)resource
;
6781 return WINED3DERR_INVALIDCALL
;
6784 /**********************************************************
6785 * IWineD3DDevice VTbl follows
6786 **********************************************************/
6788 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl
=
6790 /*** IUnknown methods ***/
6791 IWineD3DDeviceImpl_QueryInterface
,
6792 IWineD3DDeviceImpl_AddRef
,
6793 IWineD3DDeviceImpl_Release
,
6794 /*** IWineD3DDevice methods ***/
6795 IWineD3DDeviceImpl_GetParent
,
6796 /*** Creation methods**/
6797 IWineD3DDeviceImpl_CreateBuffer
,
6798 IWineD3DDeviceImpl_CreateVertexBuffer
,
6799 IWineD3DDeviceImpl_CreateIndexBuffer
,
6800 IWineD3DDeviceImpl_CreateStateBlock
,
6801 IWineD3DDeviceImpl_CreateSurface
,
6802 IWineD3DDeviceImpl_CreateRendertargetView
,
6803 IWineD3DDeviceImpl_CreateTexture
,
6804 IWineD3DDeviceImpl_CreateVolumeTexture
,
6805 IWineD3DDeviceImpl_CreateVolume
,
6806 IWineD3DDeviceImpl_CreateCubeTexture
,
6807 IWineD3DDeviceImpl_CreateQuery
,
6808 IWineD3DDeviceImpl_CreateSwapChain
,
6809 IWineD3DDeviceImpl_CreateVertexDeclaration
,
6810 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF
,
6811 IWineD3DDeviceImpl_CreateVertexShader
,
6812 IWineD3DDeviceImpl_CreateGeometryShader
,
6813 IWineD3DDeviceImpl_CreatePixelShader
,
6814 IWineD3DDeviceImpl_CreatePalette
,
6815 /*** Odd functions **/
6816 IWineD3DDeviceImpl_Init3D
,
6817 IWineD3DDeviceImpl_InitGDI
,
6818 IWineD3DDeviceImpl_Uninit3D
,
6819 IWineD3DDeviceImpl_UninitGDI
,
6820 IWineD3DDeviceImpl_SetMultithreaded
,
6821 IWineD3DDeviceImpl_EvictManagedResources
,
6822 IWineD3DDeviceImpl_GetAvailableTextureMem
,
6823 IWineD3DDeviceImpl_GetBackBuffer
,
6824 IWineD3DDeviceImpl_GetCreationParameters
,
6825 IWineD3DDeviceImpl_GetDeviceCaps
,
6826 IWineD3DDeviceImpl_GetDirect3D
,
6827 IWineD3DDeviceImpl_GetDisplayMode
,
6828 IWineD3DDeviceImpl_SetDisplayMode
,
6829 IWineD3DDeviceImpl_GetNumberOfSwapChains
,
6830 IWineD3DDeviceImpl_GetRasterStatus
,
6831 IWineD3DDeviceImpl_GetSwapChain
,
6832 IWineD3DDeviceImpl_Reset
,
6833 IWineD3DDeviceImpl_SetDialogBoxMode
,
6834 IWineD3DDeviceImpl_SetCursorProperties
,
6835 IWineD3DDeviceImpl_SetCursorPosition
,
6836 IWineD3DDeviceImpl_ShowCursor
,
6837 /*** Getters and setters **/
6838 IWineD3DDeviceImpl_SetClipPlane
,
6839 IWineD3DDeviceImpl_GetClipPlane
,
6840 IWineD3DDeviceImpl_SetClipStatus
,
6841 IWineD3DDeviceImpl_GetClipStatus
,
6842 IWineD3DDeviceImpl_SetCurrentTexturePalette
,
6843 IWineD3DDeviceImpl_GetCurrentTexturePalette
,
6844 IWineD3DDeviceImpl_SetDepthStencilSurface
,
6845 IWineD3DDeviceImpl_GetDepthStencilSurface
,
6846 IWineD3DDeviceImpl_SetGammaRamp
,
6847 IWineD3DDeviceImpl_GetGammaRamp
,
6848 IWineD3DDeviceImpl_SetIndexBuffer
,
6849 IWineD3DDeviceImpl_GetIndexBuffer
,
6850 IWineD3DDeviceImpl_SetBaseVertexIndex
,
6851 IWineD3DDeviceImpl_GetBaseVertexIndex
,
6852 IWineD3DDeviceImpl_SetLight
,
6853 IWineD3DDeviceImpl_GetLight
,
6854 IWineD3DDeviceImpl_SetLightEnable
,
6855 IWineD3DDeviceImpl_GetLightEnable
,
6856 IWineD3DDeviceImpl_SetMaterial
,
6857 IWineD3DDeviceImpl_GetMaterial
,
6858 IWineD3DDeviceImpl_SetNPatchMode
,
6859 IWineD3DDeviceImpl_GetNPatchMode
,
6860 IWineD3DDeviceImpl_SetPaletteEntries
,
6861 IWineD3DDeviceImpl_GetPaletteEntries
,
6862 IWineD3DDeviceImpl_SetPixelShader
,
6863 IWineD3DDeviceImpl_GetPixelShader
,
6864 IWineD3DDeviceImpl_SetPixelShaderConstantB
,
6865 IWineD3DDeviceImpl_GetPixelShaderConstantB
,
6866 IWineD3DDeviceImpl_SetPixelShaderConstantI
,
6867 IWineD3DDeviceImpl_GetPixelShaderConstantI
,
6868 IWineD3DDeviceImpl_SetPixelShaderConstantF
,
6869 IWineD3DDeviceImpl_GetPixelShaderConstantF
,
6870 IWineD3DDeviceImpl_SetRenderState
,
6871 IWineD3DDeviceImpl_GetRenderState
,
6872 IWineD3DDeviceImpl_SetRenderTarget
,
6873 IWineD3DDeviceImpl_GetRenderTarget
,
6874 IWineD3DDeviceImpl_SetFrontBackBuffers
,
6875 IWineD3DDeviceImpl_SetSamplerState
,
6876 IWineD3DDeviceImpl_GetSamplerState
,
6877 IWineD3DDeviceImpl_SetScissorRect
,
6878 IWineD3DDeviceImpl_GetScissorRect
,
6879 IWineD3DDeviceImpl_SetSoftwareVertexProcessing
,
6880 IWineD3DDeviceImpl_GetSoftwareVertexProcessing
,
6881 IWineD3DDeviceImpl_SetStreamSource
,
6882 IWineD3DDeviceImpl_GetStreamSource
,
6883 IWineD3DDeviceImpl_SetStreamSourceFreq
,
6884 IWineD3DDeviceImpl_GetStreamSourceFreq
,
6885 IWineD3DDeviceImpl_SetTexture
,
6886 IWineD3DDeviceImpl_GetTexture
,
6887 IWineD3DDeviceImpl_SetTextureStageState
,
6888 IWineD3DDeviceImpl_GetTextureStageState
,
6889 IWineD3DDeviceImpl_SetTransform
,
6890 IWineD3DDeviceImpl_GetTransform
,
6891 IWineD3DDeviceImpl_SetVertexDeclaration
,
6892 IWineD3DDeviceImpl_GetVertexDeclaration
,
6893 IWineD3DDeviceImpl_SetVertexShader
,
6894 IWineD3DDeviceImpl_GetVertexShader
,
6895 IWineD3DDeviceImpl_SetVertexShaderConstantB
,
6896 IWineD3DDeviceImpl_GetVertexShaderConstantB
,
6897 IWineD3DDeviceImpl_SetVertexShaderConstantI
,
6898 IWineD3DDeviceImpl_GetVertexShaderConstantI
,
6899 IWineD3DDeviceImpl_SetVertexShaderConstantF
,
6900 IWineD3DDeviceImpl_GetVertexShaderConstantF
,
6901 IWineD3DDeviceImpl_SetViewport
,
6902 IWineD3DDeviceImpl_GetViewport
,
6903 IWineD3DDeviceImpl_MultiplyTransform
,
6904 IWineD3DDeviceImpl_ValidateDevice
,
6905 IWineD3DDeviceImpl_ProcessVertices
,
6906 /*** State block ***/
6907 IWineD3DDeviceImpl_BeginStateBlock
,
6908 IWineD3DDeviceImpl_EndStateBlock
,
6909 /*** Scene management ***/
6910 IWineD3DDeviceImpl_BeginScene
,
6911 IWineD3DDeviceImpl_EndScene
,
6912 IWineD3DDeviceImpl_Present
,
6913 IWineD3DDeviceImpl_Clear
,
6914 IWineD3DDeviceImpl_ClearRendertargetView
,
6916 IWineD3DDeviceImpl_SetPrimitiveType
,
6917 IWineD3DDeviceImpl_GetPrimitiveType
,
6918 IWineD3DDeviceImpl_DrawPrimitive
,
6919 IWineD3DDeviceImpl_DrawIndexedPrimitive
,
6920 IWineD3DDeviceImpl_DrawPrimitiveUP
,
6921 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP
,
6922 IWineD3DDeviceImpl_DrawPrimitiveStrided
,
6923 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided
,
6924 IWineD3DDeviceImpl_DrawRectPatch
,
6925 IWineD3DDeviceImpl_DrawTriPatch
,
6926 IWineD3DDeviceImpl_DeletePatch
,
6927 IWineD3DDeviceImpl_ColorFill
,
6928 IWineD3DDeviceImpl_UpdateTexture
,
6929 IWineD3DDeviceImpl_UpdateSurface
,
6930 IWineD3DDeviceImpl_GetFrontBufferData
,
6931 /*** object tracking ***/
6932 IWineD3DDeviceImpl_EnumResources
,
6933 IWineD3DDeviceImpl_GetSurfaceFromDC
,
6934 IWineD3DDeviceImpl_AcquireFocusWindow
,
6935 IWineD3DDeviceImpl_ReleaseFocusWindow
,
6938 HRESULT
device_init(IWineD3DDeviceImpl
*device
, IWineD3DImpl
*wined3d
,
6939 UINT adapter_idx
, WINED3DDEVTYPE device_type
, HWND focus_window
, DWORD flags
,
6940 IUnknown
*parent
, IWineD3DDeviceParent
*device_parent
)
6942 struct wined3d_adapter
*adapter
= &wined3d
->adapters
[adapter_idx
];
6943 const struct fragment_pipeline
*fragment_pipeline
;
6944 struct shader_caps shader_caps
;
6945 struct fragment_caps ffp_caps
;
6946 WINED3DDISPLAYMODE mode
;
6950 device
->lpVtbl
= &IWineD3DDevice_Vtbl
;
6952 device
->wined3d
= (IWineD3D
*)wined3d
;
6953 IWineD3D_AddRef(device
->wined3d
);
6954 device
->adapter
= wined3d
->adapter_count
? adapter
: NULL
;
6955 device
->parent
= parent
;
6956 device
->device_parent
= device_parent
;
6957 list_init(&device
->resources
);
6958 list_init(&device
->shaders
);
6960 device
->surface_alignment
= wined3d
->dxVersion
== 7 ? DDRAW_PITCH_ALIGNMENT
: D3D8_PITCH_ALIGNMENT
;
6961 device
->posFixup
[0] = 1.0f
; /* This is needed to get the x coord unmodified through a MAD. */
6963 /* Get the initial screen setup for ddraw. */
6964 hr
= IWineD3D_GetAdapterDisplayMode((IWineD3D
*)wined3d
, adapter_idx
, &mode
);
6967 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr
);
6968 IWineD3D_Release(device
->wined3d
);
6971 device
->ddraw_width
= mode
.Width
;
6972 device
->ddraw_height
= mode
.Height
;
6973 device
->ddraw_format
= mode
.Format
;
6975 /* Save the creation parameters. */
6976 device
->createParms
.AdapterOrdinal
= adapter_idx
;
6977 device
->createParms
.DeviceType
= device_type
;
6978 device
->createParms
.hFocusWindow
= focus_window
;
6979 device
->createParms
.BehaviorFlags
= flags
;
6981 device
->devType
= device_type
;
6982 for (i
= 0; i
< PATCHMAP_SIZE
; ++i
) list_init(&device
->patches
[i
]);
6984 select_shader_mode(&adapter
->gl_info
, &device
->ps_selected_mode
, &device
->vs_selected_mode
);
6985 device
->shader_backend
= adapter
->shader_backend
;
6987 memset(&shader_caps
, 0, sizeof(shader_caps
));
6988 device
->shader_backend
->shader_get_caps(&adapter
->gl_info
, &shader_caps
);
6989 device
->d3d_vshader_constantF
= shader_caps
.MaxVertexShaderConst
;
6990 device
->d3d_pshader_constantF
= shader_caps
.MaxPixelShaderConst
;
6991 device
->vs_clipping
= shader_caps
.VSClipping
;
6993 memset(&ffp_caps
, 0, sizeof(ffp_caps
));
6994 fragment_pipeline
= adapter
->fragment_pipe
;
6995 device
->frag_pipe
= fragment_pipeline
;
6996 fragment_pipeline
->get_caps(&adapter
->gl_info
, &ffp_caps
);
6997 device
->max_ffp_textures
= ffp_caps
.MaxSimultaneousTextures
;
6999 hr
= compile_state_table(device
->StateTable
, device
->multistate_funcs
, &adapter
->gl_info
,
7000 ffp_vertexstate_template
, fragment_pipeline
, misc_state_template
);
7003 ERR("Failed to compile state table, hr %#x.\n", hr
);
7004 IWineD3D_Release(device
->wined3d
);
7008 device
->blitter
= adapter
->blitter
;
7014 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl
*This
, DWORD state
) {
7015 DWORD rep
= This
->StateTable
[state
].representative
;
7016 struct wined3d_context
*context
;
7021 for(i
= 0; i
< This
->numContexts
; i
++) {
7022 context
= This
->contexts
[i
];
7023 if(isStateDirty(context
, rep
)) continue;
7025 context
->dirtyArray
[context
->numDirtyEntries
++] = rep
;
7026 idx
= rep
/ (sizeof(*context
->isStateDirty
) * CHAR_BIT
);
7027 shift
= rep
& ((sizeof(*context
->isStateDirty
) * CHAR_BIT
) - 1);
7028 context
->isStateDirty
[idx
] |= (1 << shift
);
7032 void get_drawable_size_fbo(struct wined3d_context
*context
, UINT
*width
, UINT
*height
)
7034 IWineD3DSurfaceImpl
*surface
= (IWineD3DSurfaceImpl
*)context
->current_rt
;
7035 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7036 *width
= surface
->pow2Width
;
7037 *height
= surface
->pow2Height
;
7040 void get_drawable_size_backbuffer(struct wined3d_context
*context
, UINT
*width
, UINT
*height
)
7042 IWineD3DSwapChainImpl
*swapchain
= context
->swapchain
;
7043 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7044 * current context's drawable, which is the size of the back buffer of the swapchain
7045 * the active context belongs to. */
7046 *width
= swapchain
->presentParms
.BackBufferWidth
;
7047 *height
= swapchain
->presentParms
.BackBufferHeight
;
7050 LRESULT
device_process_message(IWineD3DDeviceImpl
*device
, HWND window
,
7051 UINT message
, WPARAM wparam
, LPARAM lparam
, WNDPROC proc
)
7053 if (device
->filter_messages
)
7055 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7056 window
, message
, wparam
, lparam
);
7057 return DefWindowProcW(window
, message
, wparam
, lparam
);
7060 if (message
== WM_DESTROY
)
7062 TRACE("unregister window %p.\n", window
);
7063 wined3d_unregister_window(window
);
7065 if (device
->focus_window
== window
) device
->focus_window
= NULL
;
7066 else ERR("Window %p is not the focus window for device %p.\n", window
, device
);
7069 return CallWindowProcW(proc
, window
, message
, wparam
, lparam
);