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-2010 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
);
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light
= {
41 WINED3DLIGHT_DIRECTIONAL
, /* Type */
42 { 1.0f
, 1.0f
, 1.0f
, 0.0f
}, /* Diffuse r,g,b,a */
43 { 0.0f
, 0.0f
, 0.0f
, 0.0f
}, /* Specular r,g,b,a */
44 { 0.0f
, 0.0f
, 0.0f
, 0.0f
}, /* Ambient r,g,b,a, */
45 { 0.0f
, 0.0f
, 0.0f
}, /* Position x,y,z */
46 { 0.0f
, 0.0f
, 1.0f
}, /* Direction x,y,z */
49 0.0f
, 0.0f
, 0.0f
, /* Attenuation 0,1,2 */
54 /**********************************************************
55 * Global variable / Constants follow
56 **********************************************************/
57 const float identity
[] =
59 1.0f
, 0.0f
, 0.0f
, 0.0f
,
60 0.0f
, 1.0f
, 0.0f
, 0.0f
,
61 0.0f
, 0.0f
, 1.0f
, 0.0f
,
62 0.0f
, 0.0f
, 0.0f
, 1.0f
,
63 }; /* When needed for comparisons */
65 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
66 * actually have the same values in GL and D3D. */
67 static GLenum
gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type
)
69 switch(primitive_type
)
71 case WINED3DPT_POINTLIST
:
74 case WINED3DPT_LINELIST
:
77 case WINED3DPT_LINESTRIP
:
80 case WINED3DPT_TRIANGLELIST
:
83 case WINED3DPT_TRIANGLESTRIP
:
84 return GL_TRIANGLE_STRIP
;
86 case WINED3DPT_TRIANGLEFAN
:
87 return GL_TRIANGLE_FAN
;
89 case WINED3DPT_LINELIST_ADJ
:
90 return GL_LINES_ADJACENCY_ARB
;
92 case WINED3DPT_LINESTRIP_ADJ
:
93 return GL_LINE_STRIP_ADJACENCY_ARB
;
95 case WINED3DPT_TRIANGLELIST_ADJ
:
96 return GL_TRIANGLES_ADJACENCY_ARB
;
98 case WINED3DPT_TRIANGLESTRIP_ADJ
:
99 return GL_TRIANGLE_STRIP_ADJACENCY_ARB
;
102 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type
));
107 static WINED3DPRIMITIVETYPE
d3d_primitive_type_from_gl(GLenum primitive_type
)
109 switch(primitive_type
)
112 return WINED3DPT_POINTLIST
;
115 return WINED3DPT_LINELIST
;
118 return WINED3DPT_LINESTRIP
;
121 return WINED3DPT_TRIANGLELIST
;
123 case GL_TRIANGLE_STRIP
:
124 return WINED3DPT_TRIANGLESTRIP
;
126 case GL_TRIANGLE_FAN
:
127 return WINED3DPT_TRIANGLEFAN
;
129 case GL_LINES_ADJACENCY_ARB
:
130 return WINED3DPT_LINELIST_ADJ
;
132 case GL_LINE_STRIP_ADJACENCY_ARB
:
133 return WINED3DPT_LINESTRIP_ADJ
;
135 case GL_TRIANGLES_ADJACENCY_ARB
:
136 return WINED3DPT_TRIANGLELIST_ADJ
;
138 case GL_TRIANGLE_STRIP_ADJACENCY_ARB
:
139 return WINED3DPT_TRIANGLESTRIP_ADJ
;
142 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type
));
143 return WINED3DPT_UNDEFINED
;
147 static BOOL
fixed_get_input(BYTE usage
, BYTE usage_idx
, unsigned int *regnum
)
149 if ((usage
== WINED3DDECLUSAGE_POSITION
|| usage
== WINED3DDECLUSAGE_POSITIONT
) && !usage_idx
)
150 *regnum
= WINED3D_FFP_POSITION
;
151 else if (usage
== WINED3DDECLUSAGE_BLENDWEIGHT
&& !usage_idx
)
152 *regnum
= WINED3D_FFP_BLENDWEIGHT
;
153 else if (usage
== WINED3DDECLUSAGE_BLENDINDICES
&& !usage_idx
)
154 *regnum
= WINED3D_FFP_BLENDINDICES
;
155 else if (usage
== WINED3DDECLUSAGE_NORMAL
&& !usage_idx
)
156 *regnum
= WINED3D_FFP_NORMAL
;
157 else if (usage
== WINED3DDECLUSAGE_PSIZE
&& !usage_idx
)
158 *regnum
= WINED3D_FFP_PSIZE
;
159 else if (usage
== WINED3DDECLUSAGE_COLOR
&& !usage_idx
)
160 *regnum
= WINED3D_FFP_DIFFUSE
;
161 else if (usage
== WINED3DDECLUSAGE_COLOR
&& usage_idx
== 1)
162 *regnum
= WINED3D_FFP_SPECULAR
;
163 else if (usage
== WINED3DDECLUSAGE_TEXCOORD
&& usage_idx
< WINED3DDP_MAXTEXCOORD
)
164 *regnum
= WINED3D_FFP_TEXCOORD0
+ usage_idx
;
167 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage
), usage_idx
);
175 /* Context activation is done by the caller. */
176 void device_stream_info_from_declaration(IWineD3DDeviceImpl
*This
,
177 BOOL use_vshader
, struct wined3d_stream_info
*stream_info
, BOOL
*fixup
)
179 /* We need to deal with frequency data! */
180 struct wined3d_vertex_declaration
*declaration
= This
->stateBlock
->state
.vertex_declaration
;
183 stream_info
->use_map
= 0;
184 stream_info
->swizzle_map
= 0;
186 /* Check for transformed vertices, disable vertex shader if present. */
187 stream_info
->position_transformed
= declaration
->position_transformed
;
188 if (declaration
->position_transformed
) use_vshader
= FALSE
;
190 /* Translate the declaration into strided data. */
191 for (i
= 0; i
< declaration
->element_count
; ++i
)
193 const struct wined3d_vertex_declaration_element
*element
= &declaration
->elements
[i
];
194 struct wined3d_buffer
*buffer
= This
->stateBlock
->state
.streams
[element
->input_slot
].buffer
;
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 (!buffer
) continue;
206 stride
= This
->stateBlock
->state
.streams
[element
->input_slot
].stride
;
207 if (This
->stateBlock
->state
.user_stream
)
209 TRACE("Stream %u is UP, %p\n", element
->input_slot
, buffer
);
211 data
= (BYTE
*)buffer
;
215 TRACE("Stream %u isn't UP, %p\n", element
->input_slot
, buffer
);
216 data
= buffer_get_memory(buffer
, &This
->adapter
->gl_info
, &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
->state
.load_base_vertex_index
< 0)
225 WARN("load_base_vertex_index is < 0 (%d), not using VBOs.\n",
226 This
->stateBlock
->state
.load_base_vertex_index
);
228 data
= buffer_get_sysmem(buffer
, &This
->adapter
->gl_info
);
229 if ((UINT_PTR
)data
< -This
->stateBlock
->state
.load_base_vertex_index
* stride
)
231 FIXME("System memory vertex data load offset is negative!\n");
237 if (buffer_object
) *fixup
= TRUE
;
238 else if (*fixup
&& !use_vshader
239 && (element
->usage
== WINED3DDECLUSAGE_COLOR
240 || element
->usage
== WINED3DDECLUSAGE_POSITIONT
))
242 static BOOL warned
= FALSE
;
245 /* This may be bad with the fixed function pipeline. */
246 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
252 data
+= element
->offset
;
254 TRACE("offset %u input_slot %u usage_idx %d\n", element
->offset
, element
->input_slot
, element
->usage_idx
);
258 if (element
->output_slot
== ~0U)
260 /* TODO: Assuming vertexdeclarations are usually used with the
261 * same or a similar shader, it might be worth it to store the
262 * last used output slot and try that one first. */
263 stride_used
= vshader_get_input(This
->stateBlock
->state
.vertex_shader
,
264 element
->usage
, element
->usage_idx
, &idx
);
268 idx
= element
->output_slot
;
274 if (!element
->ffp_valid
)
276 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
277 debug_d3dformat(element
->format
->id
), debug_d3ddeclusage(element
->usage
));
282 stride_used
= fixed_get_input(element
->usage
, element
->usage_idx
, &idx
);
288 TRACE("Load %s array %u [usage %s, usage_idx %u, "
289 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
290 use_vshader
? "shader": "fixed function", idx
,
291 debug_d3ddeclusage(element
->usage
), element
->usage_idx
, element
->input_slot
,
292 element
->offset
, stride
, debug_d3dformat(element
->format
->id
), buffer_object
);
294 stream_info
->elements
[idx
].format
= element
->format
;
295 stream_info
->elements
[idx
].stride
= stride
;
296 stream_info
->elements
[idx
].data
= data
;
297 stream_info
->elements
[idx
].stream_idx
= element
->input_slot
;
298 stream_info
->elements
[idx
].buffer_object
= buffer_object
;
300 if (!This
->adapter
->gl_info
.supported
[ARB_VERTEX_ARRAY_BGRA
]
301 && element
->format
->id
== WINED3DFMT_B8G8R8A8_UNORM
)
303 stream_info
->swizzle_map
|= 1 << idx
;
305 stream_info
->use_map
|= 1 << idx
;
309 This
->num_buffer_queries
= 0;
310 if (!This
->stateBlock
->state
.user_stream
)
312 WORD map
= stream_info
->use_map
;
314 /* PreLoad all the vertex buffers. */
315 for (i
= 0; map
; map
>>= 1, ++i
)
317 struct wined3d_stream_info_element
*element
;
318 struct wined3d_buffer
*buffer
;
320 if (!(map
& 1)) continue;
322 element
= &stream_info
->elements
[i
];
323 buffer
= This
->stateBlock
->state
.streams
[element
->stream_idx
].buffer
;
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
, &This
->adapter
->gl_info
) + (ptrdiff_t)element
->data
;
334 This
->buffer_queries
[This
->num_buffer_queries
++] = buffer
->query
;
339 static void stream_info_element_from_strided(const struct wined3d_gl_info
*gl_info
,
340 const struct WineDirect3DStridedData
*strided
, struct wined3d_stream_info_element
*e
)
342 e
->format
= wined3d_get_format(gl_info
, strided
->format
);
343 e
->stride
= strided
->dwStride
;
344 e
->data
= strided
->lpData
;
346 e
->buffer_object
= 0;
349 static void device_stream_info_from_strided(const struct wined3d_gl_info
*gl_info
,
350 const struct WineDirect3DVertexStridedData
*strided
, struct wined3d_stream_info
*stream_info
)
354 memset(stream_info
, 0, sizeof(*stream_info
));
356 if (strided
->position
.lpData
)
357 stream_info_element_from_strided(gl_info
, &strided
->position
, &stream_info
->elements
[WINED3D_FFP_POSITION
]);
358 if (strided
->normal
.lpData
)
359 stream_info_element_from_strided(gl_info
, &strided
->normal
, &stream_info
->elements
[WINED3D_FFP_NORMAL
]);
360 if (strided
->diffuse
.lpData
)
361 stream_info_element_from_strided(gl_info
, &strided
->diffuse
, &stream_info
->elements
[WINED3D_FFP_DIFFUSE
]);
362 if (strided
->specular
.lpData
)
363 stream_info_element_from_strided(gl_info
, &strided
->specular
, &stream_info
->elements
[WINED3D_FFP_SPECULAR
]);
365 for (i
= 0; i
< WINED3DDP_MAXTEXCOORD
; ++i
)
367 if (strided
->texCoords
[i
].lpData
)
368 stream_info_element_from_strided(gl_info
, &strided
->texCoords
[i
],
369 &stream_info
->elements
[WINED3D_FFP_TEXCOORD0
+ i
]);
372 stream_info
->position_transformed
= strided
->position_transformed
;
374 for (i
= 0; i
< sizeof(stream_info
->elements
) / sizeof(*stream_info
->elements
); ++i
)
376 if (!stream_info
->elements
[i
].format
) continue;
378 if (!gl_info
->supported
[ARB_VERTEX_ARRAY_BGRA
]
379 && stream_info
->elements
[i
].format
->id
== WINED3DFMT_B8G8R8A8_UNORM
)
381 stream_info
->swizzle_map
|= 1 << i
;
383 stream_info
->use_map
|= 1 << i
;
387 static void device_trace_strided_stream_info(const struct wined3d_stream_info
*stream_info
)
389 TRACE("Strided Data:\n");
390 TRACE_STRIDED(stream_info
, WINED3D_FFP_POSITION
);
391 TRACE_STRIDED(stream_info
, WINED3D_FFP_BLENDWEIGHT
);
392 TRACE_STRIDED(stream_info
, WINED3D_FFP_BLENDINDICES
);
393 TRACE_STRIDED(stream_info
, WINED3D_FFP_NORMAL
);
394 TRACE_STRIDED(stream_info
, WINED3D_FFP_PSIZE
);
395 TRACE_STRIDED(stream_info
, WINED3D_FFP_DIFFUSE
);
396 TRACE_STRIDED(stream_info
, WINED3D_FFP_SPECULAR
);
397 TRACE_STRIDED(stream_info
, WINED3D_FFP_TEXCOORD0
);
398 TRACE_STRIDED(stream_info
, WINED3D_FFP_TEXCOORD1
);
399 TRACE_STRIDED(stream_info
, WINED3D_FFP_TEXCOORD2
);
400 TRACE_STRIDED(stream_info
, WINED3D_FFP_TEXCOORD3
);
401 TRACE_STRIDED(stream_info
, WINED3D_FFP_TEXCOORD4
);
402 TRACE_STRIDED(stream_info
, WINED3D_FFP_TEXCOORD5
);
403 TRACE_STRIDED(stream_info
, WINED3D_FFP_TEXCOORD6
);
404 TRACE_STRIDED(stream_info
, WINED3D_FFP_TEXCOORD7
);
407 /* Context activation is done by the caller. */
408 void device_update_stream_info(IWineD3DDeviceImpl
*device
, const struct wined3d_gl_info
*gl_info
)
410 struct wined3d_stream_info
*stream_info
= &device
->strided_streams
;
411 const struct wined3d_state
*state
= &device
->stateBlock
->state
;
414 if (device
->up_strided
)
416 /* Note: this is a ddraw fixed-function code path. */
417 TRACE("=============================== Strided Input ================================\n");
418 device_stream_info_from_strided(gl_info
, device
->up_strided
, stream_info
);
419 if (TRACE_ON(d3d
)) device_trace_strided_stream_info(stream_info
);
423 TRACE("============================= Vertex Declaration =============================\n");
424 device_stream_info_from_declaration(device
, !!state
->vertex_shader
, stream_info
, &fixup
);
427 if (state
->vertex_shader
&& !stream_info
->position_transformed
)
429 if (state
->vertex_declaration
->half_float_conv_needed
&& !fixup
)
431 TRACE("Using drawStridedSlow with vertex shaders for FLOAT16 conversion.\n");
432 device
->useDrawStridedSlow
= TRUE
;
436 device
->useDrawStridedSlow
= FALSE
;
441 WORD slow_mask
= (1 << WINED3D_FFP_PSIZE
);
442 slow_mask
|= -!gl_info
->supported
[ARB_VERTEX_ARRAY_BGRA
]
443 & ((1 << WINED3D_FFP_DIFFUSE
) | (1 << WINED3D_FFP_SPECULAR
));
445 if ((stream_info
->position_transformed
|| (stream_info
->use_map
& slow_mask
)) && !fixup
)
447 device
->useDrawStridedSlow
= TRUE
;
451 device
->useDrawStridedSlow
= FALSE
;
456 static void device_preload_texture(const struct wined3d_state
*state
, unsigned int idx
)
458 IWineD3DBaseTextureImpl
*texture
;
459 enum WINED3DSRGB srgb
;
461 if (!(texture
= state
->textures
[idx
])) return;
462 srgb
= state
->sampler_states
[idx
][WINED3DSAMP_SRGBTEXTURE
] ? SRGB_SRGB
: SRGB_RGB
;
463 texture
->baseTexture
.texture_ops
->texture_preload(texture
, srgb
);
466 void device_preload_textures(IWineD3DDeviceImpl
*device
)
468 const struct wined3d_state
*state
= &device
->stateBlock
->state
;
473 for (i
= 0; i
< MAX_VERTEX_SAMPLERS
; ++i
)
475 if (state
->vertex_shader
->baseShader
.reg_maps
.sampler_type
[i
])
476 device_preload_texture(state
, MAX_FRAGMENT_SAMPLERS
+ i
);
482 for (i
= 0; i
< MAX_FRAGMENT_SAMPLERS
; ++i
)
484 if (state
->pixel_shader
->baseShader
.reg_maps
.sampler_type
[i
])
485 device_preload_texture(state
, i
);
490 WORD ffu_map
= device
->fixed_function_usage_map
;
492 for (i
= 0; ffu_map
; ffu_map
>>= 1, ++i
)
495 device_preload_texture(state
, i
);
500 BOOL
device_context_add(IWineD3DDeviceImpl
*device
, struct wined3d_context
*context
)
502 struct wined3d_context
**new_array
;
504 TRACE("Adding context %p.\n", context
);
506 if (!device
->contexts
) new_array
= HeapAlloc(GetProcessHeap(), 0, sizeof(*new_array
));
507 else new_array
= HeapReAlloc(GetProcessHeap(), 0, device
->contexts
, sizeof(*new_array
) * (device
->numContexts
+ 1));
511 ERR("Failed to grow the context array.\n");
515 new_array
[device
->numContexts
++] = context
;
516 device
->contexts
= new_array
;
520 void device_context_remove(IWineD3DDeviceImpl
*device
, struct wined3d_context
*context
)
522 struct wined3d_context
**new_array
;
526 TRACE("Removing context %p.\n", context
);
528 for (i
= 0; i
< device
->numContexts
; ++i
)
530 if (device
->contexts
[i
] == context
)
539 ERR("Context %p doesn't exist in context array.\n", context
);
543 if (!--device
->numContexts
)
545 HeapFree(GetProcessHeap(), 0, device
->contexts
);
546 device
->contexts
= NULL
;
550 memmove(&device
->contexts
[i
], &device
->contexts
[i
+ 1], (device
->numContexts
- i
) * sizeof(*device
->contexts
));
551 new_array
= HeapReAlloc(GetProcessHeap(), 0, device
->contexts
, device
->numContexts
* sizeof(*device
->contexts
));
554 ERR("Failed to shrink context array. Oh well.\n");
558 device
->contexts
= new_array
;
561 void device_get_draw_rect(IWineD3DDeviceImpl
*device
, RECT
*rect
)
563 struct wined3d_stateblock
*stateblock
= device
->stateBlock
;
564 WINED3DVIEWPORT
*vp
= &stateblock
->state
.viewport
;
566 SetRect(rect
, vp
->X
, vp
->Y
, vp
->X
+ vp
->Width
, vp
->Y
+ vp
->Height
);
568 if (stateblock
->state
.render_states
[WINED3DRS_SCISSORTESTENABLE
])
570 IntersectRect(rect
, rect
, &stateblock
->state
.scissor_rect
);
574 /* Do not call while under the GL lock. */
575 void device_switch_onscreen_ds(IWineD3DDeviceImpl
*device
,
576 struct wined3d_context
*context
, IWineD3DSurfaceImpl
*depth_stencil
)
578 if (device
->onscreen_depth_stencil
)
580 surface_load_ds_location(device
->onscreen_depth_stencil
, context
, SFLAG_DS_OFFSCREEN
);
581 surface_modify_ds_location(device
->onscreen_depth_stencil
, SFLAG_DS_OFFSCREEN
,
582 device
->onscreen_depth_stencil
->ds_current_size
.cx
,
583 device
->onscreen_depth_stencil
->ds_current_size
.cy
);
584 IWineD3DSurface_Release((IWineD3DSurface
*)device
->onscreen_depth_stencil
);
586 device
->onscreen_depth_stencil
= depth_stencil
;
587 IWineD3DSurface_AddRef((IWineD3DSurface
*)device
->onscreen_depth_stencil
);
590 static BOOL
is_full_clear(IWineD3DSurfaceImpl
*target
, const RECT
*draw_rect
, const RECT
*clear_rect
)
592 /* partial draw rect */
593 if (draw_rect
->left
|| draw_rect
->top
594 || draw_rect
->right
< target
->currentDesc
.Width
595 || draw_rect
->bottom
< target
->currentDesc
.Height
)
598 /* partial clear rect */
599 if (clear_rect
&& (clear_rect
->left
> 0 || clear_rect
->top
> 0
600 || clear_rect
->right
< target
->currentDesc
.Width
601 || clear_rect
->bottom
< target
->currentDesc
.Height
))
607 static void prepare_ds_clear(IWineD3DSurfaceImpl
*ds
, struct wined3d_context
*context
,
608 DWORD location
, const RECT
*draw_rect
, UINT rect_count
, const RECT
*clear_rect
)
610 RECT current_rect
, r
;
612 if (ds
->flags
& location
)
613 SetRect(¤t_rect
, 0, 0,
614 ds
->ds_current_size
.cx
,
615 ds
->ds_current_size
.cy
);
617 SetRectEmpty(¤t_rect
);
619 IntersectRect(&r
, draw_rect
, ¤t_rect
);
620 if (EqualRect(&r
, draw_rect
))
622 /* current_rect ⊇ draw_rect, modify only. */
623 surface_modify_ds_location(ds
, location
, ds
->ds_current_size
.cx
, ds
->ds_current_size
.cy
);
627 if (EqualRect(&r
, ¤t_rect
))
629 /* draw_rect ⊇ current_rect, test if we're doing a full clear. */
633 /* Full clear, modify only. */
634 surface_modify_ds_location(ds
, location
, draw_rect
->right
, draw_rect
->bottom
);
638 IntersectRect(&r
, draw_rect
, clear_rect
);
639 if (EqualRect(&r
, draw_rect
))
641 /* clear_rect ⊇ draw_rect, modify only. */
642 surface_modify_ds_location(ds
, location
, draw_rect
->right
, draw_rect
->bottom
);
648 surface_load_ds_location(ds
, context
, location
);
649 surface_modify_ds_location(ds
, location
, ds
->ds_current_size
.cx
, ds
->ds_current_size
.cy
);
652 /* Do not call while under the GL lock. */
653 HRESULT
device_clear_render_targets(IWineD3DDeviceImpl
*device
, UINT rt_count
, IWineD3DSurfaceImpl
**rts
,
654 UINT rect_count
, const RECT
*rects
, const RECT
*draw_rect
, DWORD flags
,
655 const WINED3DCOLORVALUE
*color
, float depth
, DWORD stencil
)
657 const RECT
*clear_rect
= (rect_count
> 0 && rects
) ? (const RECT
*)rects
: NULL
;
658 IWineD3DSurfaceImpl
*depth_stencil
= device
->depth_stencil
;
659 IWineD3DSurfaceImpl
*target
= rts
[0];
660 UINT drawable_width
, drawable_height
;
661 struct wined3d_context
*context
;
662 GLbitfield clear_mask
= 0;
665 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
666 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
667 * for the cleared parts, and the untouched parts.
669 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
670 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
671 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
672 * checking all this if the dest surface is in the drawable anyway. */
673 if (flags
& WINED3DCLEAR_TARGET
&& !is_full_clear(target
, draw_rect
, clear_rect
))
675 for (i
= 0; i
< rt_count
; ++i
)
677 if (rts
[i
]) surface_load_location(rts
[i
], SFLAG_INDRAWABLE
, NULL
);
681 context
= context_acquire(device
, target
);
684 context_release(context
);
685 WARN("Invalid context, skipping clear.\n");
689 if (!context_apply_clear_state(context
, device
, rt_count
, rts
, depth_stencil
))
691 context_release(context
);
692 WARN("Failed to apply clear state, skipping clear.\n");
696 target
->get_drawable_size(context
, &drawable_width
, &drawable_height
);
700 /* Only set the values up once, as they are not changing. */
701 if (flags
& WINED3DCLEAR_STENCIL
)
703 if (context
->gl_info
->supported
[EXT_STENCIL_TWO_SIDE
])
705 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT
);
706 IWineD3DDeviceImpl_MarkStateDirty(device
, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE
));
709 IWineD3DDeviceImpl_MarkStateDirty(device
, STATE_RENDER(WINED3DRS_STENCILWRITEMASK
));
710 glClearStencil(stencil
);
711 checkGLcall("glClearStencil");
712 clear_mask
= clear_mask
| GL_STENCIL_BUFFER_BIT
;
715 if (flags
& WINED3DCLEAR_ZBUFFER
)
717 DWORD location
= context
->render_offscreen
? SFLAG_DS_OFFSCREEN
: SFLAG_DS_ONSCREEN
;
719 if (location
== SFLAG_DS_ONSCREEN
&& depth_stencil
!= device
->onscreen_depth_stencil
)
722 device_switch_onscreen_ds(device
, context
, depth_stencil
);
725 prepare_ds_clear(depth_stencil
, context
, location
, draw_rect
, rect_count
, clear_rect
);
726 surface_modify_location(depth_stencil
, SFLAG_INDRAWABLE
, TRUE
);
728 glDepthMask(GL_TRUE
);
729 IWineD3DDeviceImpl_MarkStateDirty(device
, STATE_RENDER(WINED3DRS_ZWRITEENABLE
));
731 checkGLcall("glClearDepth");
732 clear_mask
= clear_mask
| GL_DEPTH_BUFFER_BIT
;
735 if (flags
& WINED3DCLEAR_TARGET
)
737 for (i
= 0; i
< rt_count
; ++i
)
739 if (rts
[i
]) surface_modify_location(rts
[i
], SFLAG_INDRAWABLE
, TRUE
);
742 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
743 IWineD3DDeviceImpl_MarkStateDirty(device
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE
));
744 IWineD3DDeviceImpl_MarkStateDirty(device
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1
));
745 IWineD3DDeviceImpl_MarkStateDirty(device
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2
));
746 IWineD3DDeviceImpl_MarkStateDirty(device
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3
));
747 glClearColor(color
->r
, color
->g
, color
->b
, color
->a
);
748 checkGLcall("glClearColor");
749 clear_mask
= clear_mask
| GL_COLOR_BUFFER_BIT
;
754 if (context
->render_offscreen
)
756 glScissor(draw_rect
->left
, draw_rect
->top
,
757 draw_rect
->right
- draw_rect
->left
, draw_rect
->bottom
- draw_rect
->top
);
761 glScissor(draw_rect
->left
, drawable_height
- draw_rect
->bottom
,
762 draw_rect
->right
- draw_rect
->left
, draw_rect
->bottom
- draw_rect
->top
);
764 checkGLcall("glScissor");
766 checkGLcall("glClear");
772 /* Now process each rect in turn. */
773 for (i
= 0; i
< rect_count
; ++i
)
775 /* Note that GL uses lower left, width/height. */
776 IntersectRect(¤t_rect
, draw_rect
, &clear_rect
[i
]);
778 TRACE("clear_rect[%u] %s, current_rect %s.\n", i
,
779 wine_dbgstr_rect(&clear_rect
[i
]),
780 wine_dbgstr_rect(¤t_rect
));
782 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
783 * The rectangle is not cleared, no error is returned, but further rectanlges are
784 * still cleared if they are valid. */
785 if (current_rect
.left
> current_rect
.right
|| current_rect
.top
> current_rect
.bottom
)
787 TRACE("Rectangle with negative dimensions, ignoring.\n");
791 if (context
->render_offscreen
)
793 glScissor(current_rect
.left
, current_rect
.top
,
794 current_rect
.right
- current_rect
.left
, current_rect
.bottom
- current_rect
.top
);
798 glScissor(current_rect
.left
, drawable_height
- current_rect
.bottom
,
799 current_rect
.right
- current_rect
.left
, current_rect
.bottom
- current_rect
.top
);
801 checkGLcall("glScissor");
804 checkGLcall("glClear");
810 if (wined3d_settings
.strict_draw_ordering
|| (target
->container
.type
== WINED3D_CONTAINER_SWAPCHAIN
811 && target
->container
.u
.swapchain
->front_buffer
== target
))
812 wglFlush(); /* Flush to ensure ordering across contexts. */
814 context_release(context
);
820 /**********************************************************
821 * IUnknown parts follows
822 **********************************************************/
824 static HRESULT WINAPI
IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice
*iface
, REFIID riid
, void **object
)
826 TRACE("iface %p, riid %s, object %p.\n", iface
, debugstr_guid(riid
), object
);
828 if (IsEqualGUID(riid
, &IID_IWineD3DDevice
)
829 || IsEqualGUID(riid
, &IID_IUnknown
))
831 IUnknown_AddRef(iface
);
836 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid
));
839 return E_NOINTERFACE
;
842 static ULONG WINAPI
IWineD3DDeviceImpl_AddRef(IWineD3DDevice
*iface
) {
843 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
844 ULONG refCount
= InterlockedIncrement(&This
->ref
);
846 TRACE("(%p) : AddRef increasing from %d\n", This
, refCount
- 1);
850 static ULONG WINAPI
IWineD3DDeviceImpl_Release(IWineD3DDevice
*iface
) {
851 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
852 ULONG refCount
= InterlockedDecrement(&This
->ref
);
854 TRACE("(%p) : Releasing from %d\n", This
, refCount
+ 1);
859 for (i
= 0; i
< sizeof(This
->multistate_funcs
)/sizeof(This
->multistate_funcs
[0]); ++i
) {
860 HeapFree(GetProcessHeap(), 0, This
->multistate_funcs
[i
]);
861 This
->multistate_funcs
[i
] = NULL
;
864 /* TODO: Clean up all the surfaces and textures! */
865 /* NOTE: You must release the parent if the object was created via a callback
866 ** ***************************/
868 if (!list_empty(&This
->resources
))
870 IWineD3DResourceImpl
*resource
;
871 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This
);
873 LIST_FOR_EACH_ENTRY(resource
, &This
->resources
, IWineD3DResourceImpl
, resource
.resource_list_entry
)
875 WINED3DRESOURCETYPE type
= IWineD3DResource_GetType((IWineD3DResource
*)resource
);
876 FIXME("Leftover resource %p with type %s (%#x).\n",
877 resource
, debug_d3dresourcetype(type
), type
);
881 if(This
->contexts
) ERR("Context array not freed!\n");
882 if (This
->hardwareCursor
) DestroyCursor(This
->hardwareCursor
);
883 This
->haveHardwareCursor
= FALSE
;
885 wined3d_decref(This
->wined3d
);
886 This
->wined3d
= NULL
;
887 HeapFree(GetProcessHeap(), 0, This
);
888 TRACE("Freed device %p\n", This
);
894 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice
*iface
, struct wined3d_buffer_desc
*desc
,
895 const void *data
, void *parent
, const struct wined3d_parent_ops
*parent_ops
, IWineD3DBuffer
**buffer
)
897 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
898 struct wined3d_buffer
*object
;
901 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface
, desc
, data
, parent
, buffer
);
903 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
906 ERR("Failed to allocate memory\n");
907 return E_OUTOFMEMORY
;
910 FIXME("Ignoring access flags (pool)\n");
912 hr
= buffer_init(object
, This
, desc
->byte_width
, desc
->usage
, WINED3DFMT_UNKNOWN
,
913 WINED3DPOOL_MANAGED
, GL_ARRAY_BUFFER_ARB
, data
, parent
, parent_ops
);
916 WARN("Failed to initialize buffer, hr %#x.\n", hr
);
917 HeapFree(GetProcessHeap(), 0, object
);
920 object
->desc
= *desc
;
922 TRACE("Created buffer %p.\n", object
);
924 *buffer
= (IWineD3DBuffer
*)object
;
929 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice
*iface
,
930 UINT Size
, DWORD Usage
, WINED3DPOOL Pool
, void *parent
,
931 const struct wined3d_parent_ops
*parent_ops
, IWineD3DBuffer
**ppVertexBuffer
)
933 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
934 struct wined3d_buffer
*object
;
937 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
938 iface
, Size
, Usage
, Pool
, ppVertexBuffer
, parent
, parent_ops
);
940 if (Pool
== WINED3DPOOL_SCRATCH
)
942 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
943 * anyway, SCRATCH vertex buffers aren't usable anywhere
945 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
946 *ppVertexBuffer
= NULL
;
947 return WINED3DERR_INVALIDCALL
;
950 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
953 ERR("Out of memory\n");
954 *ppVertexBuffer
= NULL
;
955 return WINED3DERR_OUTOFVIDEOMEMORY
;
958 hr
= buffer_init(object
, This
, Size
, Usage
, WINED3DFMT_VERTEXDATA
,
959 Pool
, GL_ARRAY_BUFFER_ARB
, NULL
, parent
, parent_ops
);
962 WARN("Failed to initialize buffer, hr %#x.\n", hr
);
963 HeapFree(GetProcessHeap(), 0, object
);
967 TRACE("Created buffer %p.\n", object
);
968 *ppVertexBuffer
= (IWineD3DBuffer
*)object
;
973 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice
*iface
,
974 UINT Length
, DWORD Usage
, WINED3DPOOL Pool
, void *parent
,
975 const struct wined3d_parent_ops
*parent_ops
, IWineD3DBuffer
**ppIndexBuffer
)
977 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
978 struct wined3d_buffer
*object
;
981 TRACE("(%p) Creating index buffer\n", This
);
983 /* Allocate the storage for the device */
984 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
987 ERR("Out of memory\n");
988 *ppIndexBuffer
= NULL
;
989 return WINED3DERR_OUTOFVIDEOMEMORY
;
992 hr
= buffer_init(object
, This
, Length
, Usage
| WINED3DUSAGE_STATICDECL
,
993 WINED3DFMT_UNKNOWN
, Pool
, GL_ELEMENT_ARRAY_BUFFER_ARB
, NULL
,
997 WARN("Failed to initialize buffer, hr %#x\n", hr
);
998 HeapFree(GetProcessHeap(), 0, object
);
1002 TRACE("Created buffer %p.\n", object
);
1004 *ppIndexBuffer
= (IWineD3DBuffer
*) object
;
1009 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice
*iface
,
1010 WINED3DSTATEBLOCKTYPE type
, struct wined3d_stateblock
**stateblock
)
1012 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1013 struct wined3d_stateblock
*object
;
1016 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1019 ERR("Failed to allocate stateblock memory.\n");
1020 return E_OUTOFMEMORY
;
1023 hr
= stateblock_init(object
, This
, type
);
1026 WARN("Failed to initialize stateblock, hr %#x.\n", hr
);
1027 HeapFree(GetProcessHeap(), 0, object
);
1031 TRACE("Created stateblock %p.\n", object
);
1032 *stateblock
= object
;
1037 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice
*iface
, UINT Width
, UINT Height
,
1038 enum wined3d_format_id Format
, BOOL Lockable
, BOOL Discard
, UINT Level
, DWORD Usage
, WINED3DPOOL Pool
,
1039 WINED3DMULTISAMPLE_TYPE MultiSample
, DWORD MultisampleQuality
, WINED3DSURFTYPE Impl
,
1040 void *parent
, const struct wined3d_parent_ops
*parent_ops
, IWineD3DSurface
**surface
)
1042 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1043 IWineD3DSurfaceImpl
*object
;
1046 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
1047 iface
, Width
, Height
, debug_d3dformat(Format
), Format
, Lockable
, Discard
, Level
);
1048 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
1049 surface
, debug_d3dusage(Usage
), Usage
, debug_d3dpool(Pool
), Pool
, MultiSample
, MultisampleQuality
);
1050 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl
, parent
, parent_ops
);
1052 if (Impl
== SURFACE_OPENGL
&& !This
->adapter
)
1054 ERR("OpenGL surfaces are not available without OpenGL.\n");
1055 return WINED3DERR_NOTAVAILABLE
;
1058 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1061 ERR("Failed to allocate surface memory.\n");
1062 return WINED3DERR_OUTOFVIDEOMEMORY
;
1065 hr
= surface_init(object
, Impl
, This
->surface_alignment
, Width
, Height
, Level
, Lockable
,
1066 Discard
, MultiSample
, MultisampleQuality
, This
, Usage
, Format
, Pool
, parent
, parent_ops
);
1069 WARN("Failed to initialize surface, returning %#x.\n", hr
);
1070 HeapFree(GetProcessHeap(), 0, object
);
1074 TRACE("(%p) : Created surface %p\n", This
, object
);
1076 *surface
= (IWineD3DSurface
*)object
;
1081 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice
*iface
,
1082 IWineD3DResource
*resource
, void *parent
, IWineD3DRendertargetView
**rendertarget_view
)
1084 struct wined3d_rendertarget_view
*object
;
1086 TRACE("iface %p, resource %p, parent %p, rendertarget_view %p.\n",
1087 iface
, resource
, parent
, rendertarget_view
);
1089 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1092 ERR("Failed to allocate memory\n");
1093 return E_OUTOFMEMORY
;
1096 wined3d_rendertarget_view_init(object
, (IWineD3DResourceImpl
*)resource
, parent
);
1098 TRACE("Created render target view %p.\n", object
);
1099 *rendertarget_view
= (IWineD3DRendertargetView
*)object
;
1104 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice
*iface
,
1105 UINT Width
, UINT Height
, UINT Levels
, DWORD Usage
, enum wined3d_format_id Format
, WINED3DPOOL Pool
,
1106 void *parent
, const struct wined3d_parent_ops
*parent_ops
, IWineD3DTexture
**ppTexture
)
1108 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1109 IWineD3DTextureImpl
*object
;
1112 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This
, Width
, Height
, Levels
, Usage
);
1113 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
1114 Format
, debug_d3dformat(Format
), Pool
, ppTexture
, parent
);
1116 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1119 ERR("Out of memory\n");
1121 return WINED3DERR_OUTOFVIDEOMEMORY
;
1124 hr
= texture_init(object
, Width
, Height
, Levels
, This
, Usage
, Format
, Pool
, parent
, parent_ops
);
1127 WARN("Failed to initialize texture, returning %#x\n", hr
);
1128 HeapFree(GetProcessHeap(), 0, object
);
1133 *ppTexture
= (IWineD3DTexture
*)object
;
1135 TRACE("(%p) : Created texture %p\n", This
, object
);
1140 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice
*iface
,
1141 UINT Width
, UINT Height
, UINT Depth
, UINT Levels
, DWORD Usage
, enum wined3d_format_id Format
, WINED3DPOOL Pool
,
1142 void *parent
, const struct wined3d_parent_ops
*parent_ops
, IWineD3DVolumeTexture
**ppVolumeTexture
)
1144 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1145 IWineD3DVolumeTextureImpl
*object
;
1148 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
1149 Depth
, Levels
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
1151 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1154 ERR("Out of memory\n");
1155 *ppVolumeTexture
= NULL
;
1156 return WINED3DERR_OUTOFVIDEOMEMORY
;
1159 hr
= volumetexture_init(object
, Width
, Height
, Depth
, Levels
, This
, Usage
, Format
, Pool
, parent
, parent_ops
);
1162 WARN("Failed to initialize volumetexture, returning %#x\n", hr
);
1163 HeapFree(GetProcessHeap(), 0, object
);
1164 *ppVolumeTexture
= NULL
;
1168 TRACE("(%p) : Created volume texture %p.\n", This
, object
);
1169 *ppVolumeTexture
= (IWineD3DVolumeTexture
*)object
;
1174 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice
*iface
, UINT Width
, UINT Height
,
1175 UINT Depth
, DWORD Usage
, enum wined3d_format_id Format
, WINED3DPOOL Pool
, void *parent
,
1176 const struct wined3d_parent_ops
*parent_ops
, IWineD3DVolume
**ppVolume
)
1178 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1179 IWineD3DVolumeImpl
*object
;
1182 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
1183 Depth
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
1185 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1188 ERR("Out of memory\n");
1190 return WINED3DERR_OUTOFVIDEOMEMORY
;
1193 hr
= volume_init(object
, This
, Width
, Height
, Depth
, Usage
, Format
, Pool
, parent
, parent_ops
);
1196 WARN("Failed to initialize volume, returning %#x.\n", hr
);
1197 HeapFree(GetProcessHeap(), 0, object
);
1201 TRACE("(%p) : Created volume %p.\n", This
, object
);
1202 *ppVolume
= (IWineD3DVolume
*)object
;
1207 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice
*iface
, UINT EdgeLength
, UINT Levels
,
1208 DWORD Usage
, enum wined3d_format_id Format
, WINED3DPOOL Pool
, void *parent
,
1209 const struct wined3d_parent_ops
*parent_ops
, IWineD3DCubeTexture
**ppCubeTexture
)
1211 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1212 IWineD3DCubeTextureImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1215 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1218 ERR("Out of memory\n");
1219 *ppCubeTexture
= NULL
;
1220 return WINED3DERR_OUTOFVIDEOMEMORY
;
1223 hr
= cubetexture_init(object
, EdgeLength
, Levels
, This
, Usage
, Format
, Pool
, parent
, parent_ops
);
1226 WARN("Failed to initialize cubetexture, returning %#x\n", hr
);
1227 HeapFree(GetProcessHeap(), 0, object
);
1228 *ppCubeTexture
= NULL
;
1232 TRACE("(%p) : Created Cube Texture %p\n", This
, object
);
1233 *ppCubeTexture
= (IWineD3DCubeTexture
*)object
;
1238 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice
*iface
,
1239 WINED3DQUERYTYPE type
, IWineD3DQuery
**query
)
1241 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1242 IWineD3DQueryImpl
*object
;
1245 TRACE("iface %p, type %#x, query %p.\n", iface
, type
, query
);
1247 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1250 ERR("Failed to allocate query memory.\n");
1251 return E_OUTOFMEMORY
;
1254 hr
= query_init(object
, This
, type
);
1257 WARN("Failed to initialize query, hr %#x.\n", hr
);
1258 HeapFree(GetProcessHeap(), 0, object
);
1262 TRACE("Created query %p.\n", object
);
1263 *query
= (IWineD3DQuery
*)object
;
1268 /* Do not call while under the GL lock. */
1269 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice
*iface
,
1270 WINED3DPRESENT_PARAMETERS
*present_parameters
, WINED3DSURFTYPE surface_type
,
1271 void *parent
, IWineD3DSwapChain
**swapchain
)
1273 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1274 IWineD3DSwapChainImpl
*object
;
1277 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1278 iface
, present_parameters
, swapchain
, parent
, surface_type
);
1280 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1283 ERR("Failed to allocate swapchain memory.\n");
1284 return E_OUTOFMEMORY
;
1287 hr
= swapchain_init(object
, surface_type
, This
, present_parameters
, parent
);
1290 WARN("Failed to initialize swapchain, hr %#x.\n", hr
);
1291 HeapFree(GetProcessHeap(), 0, object
);
1295 TRACE("Created swapchain %p.\n", object
);
1296 *swapchain
= (IWineD3DSwapChain
*)object
;
1301 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1302 static UINT WINAPI
IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice
*iface
) {
1303 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1304 TRACE("(%p)\n", This
);
1306 return This
->NumberOfSwapChains
;
1309 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice
*iface
, UINT iSwapChain
, IWineD3DSwapChain
**pSwapChain
) {
1310 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1311 TRACE("(%p) : swapchain %d\n", This
, iSwapChain
);
1313 if (iSwapChain
< This
->NumberOfSwapChains
)
1315 *pSwapChain
= (IWineD3DSwapChain
*)This
->swapchains
[iSwapChain
];
1316 IWineD3DSwapChain_AddRef(*pSwapChain
);
1317 TRACE("(%p) returning %p\n", This
, *pSwapChain
);
1320 TRACE("Swapchain out of range\n");
1322 return WINED3DERR_INVALIDCALL
;
1326 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice
*iface
,
1327 const WINED3DVERTEXELEMENT
*elements
, UINT element_count
, void *parent
,
1328 const struct wined3d_parent_ops
*parent_ops
, struct wined3d_vertex_declaration
**declaration
)
1330 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1331 struct wined3d_vertex_declaration
*object
;
1334 TRACE("iface %p, elements %p, element_count %u, parent %p, parent_ops %p, declaration %p.\n",
1335 iface
, elements
, element_count
, parent
, parent_ops
, declaration
);
1337 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1340 ERR("Failed to allocate vertex declaration memory.\n");
1341 return E_OUTOFMEMORY
;
1344 hr
= vertexdeclaration_init(object
, This
, elements
, element_count
, parent
, parent_ops
);
1347 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr
);
1348 HeapFree(GetProcessHeap(), 0, object
);
1352 TRACE("Created vertex declaration %p.\n", object
);
1353 *declaration
= object
;
1358 struct wined3d_fvf_convert_state
1360 const struct wined3d_gl_info
*gl_info
;
1361 WINED3DVERTEXELEMENT
*elements
;
1366 static void append_decl_element(struct wined3d_fvf_convert_state
*state
,
1367 enum wined3d_format_id format_id
, WINED3DDECLUSAGE usage
, UINT usage_idx
)
1369 WINED3DVERTEXELEMENT
*elements
= state
->elements
;
1370 const struct wined3d_format
*format
;
1371 UINT offset
= state
->offset
;
1372 UINT idx
= state
->idx
;
1374 elements
[idx
].format
= format_id
;
1375 elements
[idx
].input_slot
= 0;
1376 elements
[idx
].offset
= offset
;
1377 elements
[idx
].output_slot
= 0;
1378 elements
[idx
].method
= WINED3DDECLMETHOD_DEFAULT
;
1379 elements
[idx
].usage
= usage
;
1380 elements
[idx
].usage_idx
= usage_idx
;
1382 format
= wined3d_get_format(state
->gl_info
, format_id
);
1383 state
->offset
+= format
->component_count
* format
->component_size
;
1387 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl
*This
, /* For the GL info, which has the type table */
1388 DWORD fvf
, WINED3DVERTEXELEMENT
**ppVertexElements
)
1390 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
1391 BOOL has_pos
= !!(fvf
& WINED3DFVF_POSITION_MASK
);
1392 BOOL has_blend
= (fvf
& WINED3DFVF_XYZB5
) > WINED3DFVF_XYZRHW
;
1393 BOOL has_blend_idx
= has_blend
&&
1394 (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB5
) ||
1395 (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
) ||
1396 (fvf
& WINED3DFVF_LASTBETA_UBYTE4
));
1397 BOOL has_normal
= !!(fvf
& WINED3DFVF_NORMAL
);
1398 BOOL has_psize
= !!(fvf
& WINED3DFVF_PSIZE
);
1399 BOOL has_diffuse
= !!(fvf
& WINED3DFVF_DIFFUSE
);
1400 BOOL has_specular
= !!(fvf
& WINED3DFVF_SPECULAR
);
1402 DWORD num_textures
= (fvf
& WINED3DFVF_TEXCOUNT_MASK
) >> WINED3DFVF_TEXCOUNT_SHIFT
;
1403 DWORD texcoords
= (fvf
& 0xFFFF0000) >> 16;
1404 struct wined3d_fvf_convert_state state
;
1407 DWORD num_blends
= 1 + (((fvf
& WINED3DFVF_XYZB5
) - WINED3DFVF_XYZB1
) >> 1);
1408 if (has_blend_idx
) num_blends
--;
1410 /* Compute declaration size */
1411 size
= has_pos
+ (has_blend
&& num_blends
> 0) + has_blend_idx
+ has_normal
+
1412 has_psize
+ has_diffuse
+ has_specular
+ num_textures
;
1414 state
.gl_info
= gl_info
;
1415 state
.elements
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(*state
.elements
));
1416 if (!state
.elements
) return ~0U;
1422 if (!has_blend
&& (fvf
& WINED3DFVF_XYZRHW
))
1423 append_decl_element(&state
, WINED3DFMT_R32G32B32A32_FLOAT
, WINED3DDECLUSAGE_POSITIONT
, 0);
1424 else if ((fvf
& WINED3DFVF_XYZW
) == WINED3DFVF_XYZW
)
1425 append_decl_element(&state
, WINED3DFMT_R32G32B32A32_FLOAT
, WINED3DDECLUSAGE_POSITION
, 0);
1427 append_decl_element(&state
, WINED3DFMT_R32G32B32_FLOAT
, WINED3DDECLUSAGE_POSITION
, 0);
1430 if (has_blend
&& (num_blends
> 0))
1432 if ((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB2
&& (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
))
1433 append_decl_element(&state
, WINED3DFMT_B8G8R8A8_UNORM
, WINED3DDECLUSAGE_BLENDWEIGHT
, 0);
1439 append_decl_element(&state
, WINED3DFMT_R32_FLOAT
, WINED3DDECLUSAGE_BLENDWEIGHT
, 0);
1442 append_decl_element(&state
, WINED3DFMT_R32G32_FLOAT
, WINED3DDECLUSAGE_BLENDWEIGHT
, 0);
1445 append_decl_element(&state
, WINED3DFMT_R32G32B32_FLOAT
, WINED3DDECLUSAGE_BLENDWEIGHT
, 0);
1448 append_decl_element(&state
, WINED3DFMT_R32G32B32A32_FLOAT
, WINED3DDECLUSAGE_BLENDWEIGHT
, 0);
1451 ERR("Unexpected amount of blend values: %u\n", num_blends
);
1458 if ((fvf
& WINED3DFVF_LASTBETA_UBYTE4
)
1459 || ((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB2
&& (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
)))
1460 append_decl_element(&state
, WINED3DFMT_R8G8B8A8_UINT
, WINED3DDECLUSAGE_BLENDINDICES
, 0);
1461 else if (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
)
1462 append_decl_element(&state
, WINED3DFMT_B8G8R8A8_UNORM
, WINED3DDECLUSAGE_BLENDINDICES
, 0);
1464 append_decl_element(&state
, WINED3DFMT_R32_FLOAT
, WINED3DDECLUSAGE_BLENDINDICES
, 0);
1467 if (has_normal
) append_decl_element(&state
, WINED3DFMT_R32G32B32_FLOAT
, WINED3DDECLUSAGE_NORMAL
, 0);
1468 if (has_psize
) append_decl_element(&state
, WINED3DFMT_R32_FLOAT
, WINED3DDECLUSAGE_PSIZE
, 0);
1469 if (has_diffuse
) append_decl_element(&state
, WINED3DFMT_B8G8R8A8_UNORM
, WINED3DDECLUSAGE_COLOR
, 0);
1470 if (has_specular
) append_decl_element(&state
, WINED3DFMT_B8G8R8A8_UNORM
, WINED3DDECLUSAGE_COLOR
, 1);
1472 for (idx
= 0; idx
< num_textures
; ++idx
)
1474 switch ((texcoords
>> (idx
* 2)) & 0x03)
1476 case WINED3DFVF_TEXTUREFORMAT1
:
1477 append_decl_element(&state
, WINED3DFMT_R32_FLOAT
, WINED3DDECLUSAGE_TEXCOORD
, idx
);
1479 case WINED3DFVF_TEXTUREFORMAT2
:
1480 append_decl_element(&state
, WINED3DFMT_R32G32_FLOAT
, WINED3DDECLUSAGE_TEXCOORD
, idx
);
1482 case WINED3DFVF_TEXTUREFORMAT3
:
1483 append_decl_element(&state
, WINED3DFMT_R32G32B32_FLOAT
, WINED3DDECLUSAGE_TEXCOORD
, idx
);
1485 case WINED3DFVF_TEXTUREFORMAT4
:
1486 append_decl_element(&state
, WINED3DFMT_R32G32B32A32_FLOAT
, WINED3DDECLUSAGE_TEXCOORD
, idx
);
1491 *ppVertexElements
= state
.elements
;
1495 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice
*iface
,
1496 DWORD fvf
, void *parent
, const struct wined3d_parent_ops
*parent_ops
,
1497 struct wined3d_vertex_declaration
**declaration
)
1499 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1500 WINED3DVERTEXELEMENT
*elements
;
1504 TRACE("iface %p, fvf %#x, parent %p, parent_ops %p, declaration %p.\n",
1505 iface
, fvf
, parent
, parent_ops
, declaration
);
1507 size
= ConvertFvfToDeclaration(This
, fvf
, &elements
);
1508 if (size
== ~0U) return E_OUTOFMEMORY
;
1510 hr
= IWineD3DDeviceImpl_CreateVertexDeclaration(iface
, elements
, size
, parent
, parent_ops
, declaration
);
1511 HeapFree(GetProcessHeap(), 0, elements
);
1515 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice
*iface
,
1516 const DWORD
*pFunction
, const struct wined3d_shader_signature
*output_signature
,
1517 void *parent
, const struct wined3d_parent_ops
*parent_ops
,
1518 IWineD3DVertexShader
**ppVertexShader
)
1520 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1521 IWineD3DVertexShaderImpl
*object
;
1524 if (This
->vs_selected_mode
== SHADER_NONE
)
1525 return WINED3DERR_INVALIDCALL
;
1527 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1530 ERR("Failed to allocate shader memory.\n");
1531 return E_OUTOFMEMORY
;
1534 hr
= vertexshader_init(object
, This
, pFunction
, output_signature
, parent
, parent_ops
);
1537 WARN("Failed to initialize vertex shader, hr %#x.\n", hr
);
1538 HeapFree(GetProcessHeap(), 0, object
);
1542 TRACE("Created vertex shader %p.\n", object
);
1543 *ppVertexShader
= (IWineD3DVertexShader
*)object
;
1548 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice
*iface
,
1549 const DWORD
*byte_code
, const struct wined3d_shader_signature
*output_signature
,
1550 void *parent
, const struct wined3d_parent_ops
*parent_ops
,
1551 IWineD3DGeometryShader
**shader
)
1553 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1554 struct wined3d_geometryshader
*object
;
1557 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1560 ERR("Failed to allocate shader memory.\n");
1561 return E_OUTOFMEMORY
;
1564 hr
= geometryshader_init(object
, This
, byte_code
, output_signature
, parent
, parent_ops
);
1567 WARN("Failed to initialize geometry shader, hr %#x.\n", hr
);
1568 HeapFree(GetProcessHeap(), 0, object
);
1572 TRACE("Created geometry shader %p.\n", object
);
1573 *shader
= (IWineD3DGeometryShader
*)object
;
1578 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice
*iface
,
1579 const DWORD
*pFunction
, const struct wined3d_shader_signature
*output_signature
,
1580 void *parent
, const struct wined3d_parent_ops
*parent_ops
,
1581 IWineD3DPixelShader
**ppPixelShader
)
1583 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1584 IWineD3DPixelShaderImpl
*object
;
1587 if (This
->ps_selected_mode
== SHADER_NONE
)
1588 return WINED3DERR_INVALIDCALL
;
1590 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1593 ERR("Failed to allocate shader memory.\n");
1594 return E_OUTOFMEMORY
;
1597 hr
= pixelshader_init(object
, This
, pFunction
, output_signature
, parent
, parent_ops
);
1600 WARN("Failed to initialize pixel shader, hr %#x.\n", hr
);
1601 HeapFree(GetProcessHeap(), 0, object
);
1605 TRACE("Created pixel shader %p.\n", object
);
1606 *ppPixelShader
= (IWineD3DPixelShader
*)object
;
1611 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice
*iface
, DWORD flags
,
1612 const PALETTEENTRY
*PalEnt
, void *parent
, IWineD3DPalette
**Palette
)
1614 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1615 IWineD3DPaletteImpl
*object
;
1618 TRACE("iface %p, flags %#x, entries %p, palette %p, parent %p.\n",
1619 iface
, flags
, PalEnt
, Palette
, parent
);
1621 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1624 ERR("Failed to allocate palette memory.\n");
1625 return E_OUTOFMEMORY
;
1628 hr
= wined3d_palette_init(object
, This
, flags
, PalEnt
, parent
);
1631 WARN("Failed to initialize palette, hr %#x.\n", hr
);
1632 HeapFree(GetProcessHeap(), 0, object
);
1636 TRACE("Created palette %p.\n", object
);
1637 *Palette
= (IWineD3DPalette
*)object
;
1642 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl
*This
, const char *filename
) {
1646 HDC dcb
= NULL
, dcs
= NULL
;
1647 WINEDDCOLORKEY colorkey
;
1649 hbm
= LoadImageA(NULL
, filename
, IMAGE_BITMAP
, 0, 0, LR_LOADFROMFILE
| LR_CREATEDIBSECTION
);
1652 GetObjectA(hbm
, sizeof(BITMAP
), &bm
);
1653 dcb
= CreateCompatibleDC(NULL
);
1655 SelectObject(dcb
, hbm
);
1659 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1660 * couldn't be loaded
1662 memset(&bm
, 0, sizeof(bm
));
1667 hr
= IWineD3DDevice_CreateSurface((IWineD3DDevice
*)This
, bm
.bmWidth
, bm
.bmHeight
, WINED3DFMT_B5G6R5_UNORM
, TRUE
,
1668 FALSE
, 0, 0, WINED3DPOOL_DEFAULT
, WINED3DMULTISAMPLE_NONE
, 0, SURFACE_OPENGL
, NULL
,
1669 &wined3d_null_parent_ops
, &This
->logo_surface
);
1672 ERR("Wine logo requested, but failed to create surface, hr %#x.\n", hr
);
1677 hr
= IWineD3DSurface_GetDC(This
->logo_surface
, &dcs
);
1678 if(FAILED(hr
)) goto out
;
1679 BitBlt(dcs
, 0, 0, bm
.bmWidth
, bm
.bmHeight
, dcb
, 0, 0, SRCCOPY
);
1680 IWineD3DSurface_ReleaseDC(This
->logo_surface
, dcs
);
1682 colorkey
.dwColorSpaceLowValue
= 0;
1683 colorkey
.dwColorSpaceHighValue
= 0;
1684 IWineD3DSurface_SetColorKey(This
->logo_surface
, WINEDDCKEY_SRCBLT
, &colorkey
);
1688 const WINED3DCOLORVALUE c
= {1.0f
, 1.0f
, 1.0f
, 1.0f
};
1689 /* Fill the surface with a white color to show that wined3d is there */
1690 IWineD3DDevice_ColorFill((IWineD3DDevice
*)This
, This
->logo_surface
, NULL
, &c
);
1694 if (dcb
) DeleteDC(dcb
);
1695 if (hbm
) DeleteObject(hbm
);
1698 /* Context activation is done by the caller. */
1699 static void create_dummy_textures(IWineD3DDeviceImpl
*This
)
1701 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
1703 /* Under DirectX you can have texture stage operations even if no texture is
1704 bound, whereas opengl will only do texture operations when a valid texture is
1705 bound. We emulate this by creating dummy textures and binding them to each
1706 texture stage, but disable all stages by default. Hence if a stage is enabled
1707 then the default texture will kick in until replaced by a SetTexture call */
1710 if (gl_info
->supported
[APPLE_CLIENT_STORAGE
])
1712 /* The dummy texture does not have client storage backing */
1713 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
1714 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1717 for (i
= 0; i
< gl_info
->limits
.textures
; ++i
)
1719 GLubyte white
= 255;
1721 /* Make appropriate texture active */
1722 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
+ i
));
1723 checkGLcall("glActiveTextureARB");
1725 /* Generate an opengl texture name */
1726 glGenTextures(1, &This
->dummyTextureName
[i
]);
1727 checkGLcall("glGenTextures");
1728 TRACE("Dummy Texture %d given name %d\n", i
, This
->dummyTextureName
[i
]);
1730 /* Generate a dummy 2d texture (not using 1d because they cause many
1731 * DRI drivers fall back to sw) */
1732 glBindTexture(GL_TEXTURE_2D
, This
->dummyTextureName
[i
]);
1733 checkGLcall("glBindTexture");
1735 glTexImage2D(GL_TEXTURE_2D
, 0, GL_LUMINANCE
, 1, 1, 0, GL_LUMINANCE
, GL_UNSIGNED_BYTE
, &white
);
1736 checkGLcall("glTexImage2D");
1739 if (gl_info
->supported
[APPLE_CLIENT_STORAGE
])
1741 /* Reenable because if supported it is enabled by default */
1742 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
1743 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1749 /* Context activation is done by the caller. */
1750 static void destroy_dummy_textures(IWineD3DDeviceImpl
*device
, const struct wined3d_gl_info
*gl_info
)
1753 glDeleteTextures(gl_info
->limits
.textures
, device
->dummyTextureName
);
1754 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1757 memset(device
->dummyTextureName
, 0, gl_info
->limits
.textures
* sizeof(*device
->dummyTextureName
));
1760 static LONG
fullscreen_style(LONG style
)
1762 /* Make sure the window is managed, otherwise we won't get keyboard input. */
1763 style
|= WS_POPUP
| WS_SYSMENU
;
1764 style
&= ~(WS_CAPTION
| WS_THICKFRAME
);
1769 static LONG
fullscreen_exstyle(LONG exstyle
)
1771 /* Filter out window decorations. */
1772 exstyle
&= ~(WS_EX_WINDOWEDGE
| WS_EX_CLIENTEDGE
);
1777 static void WINAPI
IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice
*iface
, HWND window
, UINT w
, UINT h
)
1779 IWineD3DDeviceImpl
*device
= (IWineD3DDeviceImpl
*)iface
;
1780 BOOL filter_messages
;
1781 LONG style
, exstyle
;
1783 TRACE("Setting up window %p for fullscreen mode.\n", window
);
1785 if (device
->style
|| device
->exStyle
)
1787 ERR("Changing the window style for window %p, but another style (%08x, %08x) is already stored.\n",
1788 window
, device
->style
, device
->exStyle
);
1791 device
->style
= GetWindowLongW(window
, GWL_STYLE
);
1792 device
->exStyle
= GetWindowLongW(window
, GWL_EXSTYLE
);
1794 style
= fullscreen_style(device
->style
);
1795 exstyle
= fullscreen_exstyle(device
->exStyle
);
1797 TRACE("Old style was %08x, %08x, setting to %08x, %08x.\n",
1798 device
->style
, device
->exStyle
, style
, exstyle
);
1800 filter_messages
= device
->filter_messages
;
1801 device
->filter_messages
= TRUE
;
1803 SetWindowLongW(window
, GWL_STYLE
, style
);
1804 SetWindowLongW(window
, GWL_EXSTYLE
, exstyle
);
1805 SetWindowPos(window
, HWND_TOP
, 0, 0, w
, h
, SWP_FRAMECHANGED
| SWP_SHOWWINDOW
| SWP_NOACTIVATE
);
1807 device
->filter_messages
= filter_messages
;
1810 static void WINAPI
IWineD3DDeviceImpl_RestoreFullscreenWindow(IWineD3DDevice
*iface
, HWND window
)
1812 IWineD3DDeviceImpl
*device
= (IWineD3DDeviceImpl
*)iface
;
1813 BOOL filter_messages
;
1814 LONG style
, exstyle
;
1816 if (!device
->style
&& !device
->exStyle
) return;
1818 TRACE("Restoring window style of window %p to %08x, %08x.\n",
1819 window
, device
->style
, device
->exStyle
);
1821 style
= GetWindowLongW(window
, GWL_STYLE
);
1822 exstyle
= GetWindowLongW(window
, GWL_EXSTYLE
);
1824 filter_messages
= device
->filter_messages
;
1825 device
->filter_messages
= TRUE
;
1827 /* Only restore the style if the application didn't modify it during the
1828 * fullscreen phase. Some applications change it before calling Reset()
1829 * when switching between windowed and fullscreen modes (HL2), some
1830 * depend on the original style (Eve Online). */
1831 if (style
== fullscreen_style(device
->style
) && exstyle
== fullscreen_exstyle(device
->exStyle
))
1833 SetWindowLongW(window
, GWL_STYLE
, device
->style
);
1834 SetWindowLongW(window
, GWL_EXSTYLE
, device
->exStyle
);
1836 SetWindowPos(window
, 0, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
1838 device
->filter_messages
= filter_messages
;
1840 /* Delete the old values. */
1842 device
->exStyle
= 0;
1845 static HRESULT WINAPI
IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice
*iface
, HWND window
)
1847 IWineD3DDeviceImpl
*device
= (IWineD3DDeviceImpl
*)iface
;
1849 TRACE("iface %p, window %p.\n", iface
, window
);
1851 if (!wined3d_register_window(window
, device
))
1853 ERR("Failed to register window %p.\n", window
);
1857 device
->focus_window
= window
;
1858 SetWindowPos(window
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
);
1863 static void WINAPI
IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice
*iface
)
1865 IWineD3DDeviceImpl
*device
= (IWineD3DDeviceImpl
*)iface
;
1867 TRACE("iface %p.\n", iface
);
1869 if (device
->focus_window
) wined3d_unregister_window(device
->focus_window
);
1870 device
->focus_window
= NULL
;
1873 static HRESULT WINAPI
IWineD3DDeviceImpl_Init3D(IWineD3DDevice
*iface
,
1874 WINED3DPRESENT_PARAMETERS
*pPresentationParameters
)
1876 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
1877 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
1878 IWineD3DSwapChainImpl
*swapchain
= NULL
;
1879 struct wined3d_context
*context
;
1884 TRACE("(%p)->(%p)\n", This
, pPresentationParameters
);
1886 if(This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
1887 if(!This
->adapter
->opengl
) return WINED3DERR_INVALIDCALL
;
1889 TRACE("(%p) : Creating stateblock\n", This
);
1890 hr
= IWineD3DDevice_CreateStateBlock(iface
, WINED3DSBT_INIT
, &This
->stateBlock
);
1893 WARN("Failed to create stateblock\n");
1896 TRACE("(%p) : Created stateblock (%p)\n", This
, This
->stateBlock
);
1897 This
->updateStateBlock
= This
->stateBlock
;
1898 wined3d_stateblock_incref(This
->updateStateBlock
);
1900 This
->render_targets
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
1901 sizeof(*This
->render_targets
) * gl_info
->limits
.buffers
);
1903 This
->NumberOfPalettes
= 1;
1904 This
->palettes
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(PALETTEENTRY
*));
1905 if (!This
->palettes
|| !This
->render_targets
)
1907 ERR("Out of memory!\n");
1911 This
->palettes
[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY
) * 256);
1912 if(!This
->palettes
[0]) {
1913 ERR("Out of memory!\n");
1917 for (i
= 0; i
< 256; ++i
) {
1918 This
->palettes
[0][i
].peRed
= 0xFF;
1919 This
->palettes
[0][i
].peGreen
= 0xFF;
1920 This
->palettes
[0][i
].peBlue
= 0xFF;
1921 This
->palettes
[0][i
].peFlags
= 0xFF;
1923 This
->currentPalette
= 0;
1925 /* Initialize the texture unit mapping to a 1:1 mapping */
1926 for (state
= 0; state
< MAX_COMBINED_SAMPLERS
; ++state
)
1928 if (state
< gl_info
->limits
.fragment_samplers
)
1930 This
->texUnitMap
[state
] = state
;
1931 This
->rev_tex_unit_map
[state
] = state
;
1933 This
->texUnitMap
[state
] = WINED3D_UNMAPPED_STAGE
;
1934 This
->rev_tex_unit_map
[state
] = WINED3D_UNMAPPED_STAGE
;
1938 /* Setup the implicit swapchain. This also initializes a context. */
1939 TRACE("Creating implicit swapchain\n");
1940 hr
= IWineD3DDeviceParent_CreateSwapChain(This
->device_parent
,
1941 pPresentationParameters
, (IWineD3DSwapChain
**)&swapchain
);
1944 WARN("Failed to create implicit swapchain\n");
1948 This
->NumberOfSwapChains
= 1;
1949 This
->swapchains
= HeapAlloc(GetProcessHeap(), 0, This
->NumberOfSwapChains
* sizeof(*This
->swapchains
));
1950 if (!This
->swapchains
)
1952 ERR("Out of memory!\n");
1955 This
->swapchains
[0] = swapchain
;
1957 if (swapchain
->back_buffers
&& swapchain
->back_buffers
[0])
1959 TRACE("Setting rendertarget to %p.\n", swapchain
->back_buffers
);
1960 This
->render_targets
[0] = swapchain
->back_buffers
[0];
1964 TRACE("Setting rendertarget to %p.\n", swapchain
->front_buffer
);
1965 This
->render_targets
[0] = swapchain
->front_buffer
;
1967 IWineD3DSurface_AddRef((IWineD3DSurface
*)This
->render_targets
[0]);
1969 /* Depth Stencil support */
1970 This
->depth_stencil
= This
->auto_depth_stencil
;
1971 if (This
->depth_stencil
)
1972 IWineD3DSurface_AddRef((IWineD3DSurface
*)This
->depth_stencil
);
1974 hr
= This
->shader_backend
->shader_alloc_private(This
);
1976 TRACE("Shader private data couldn't be allocated\n");
1979 hr
= This
->frag_pipe
->alloc_private(This
);
1981 TRACE("Fragment pipeline private data couldn't be allocated\n");
1984 hr
= This
->blitter
->alloc_private(This
);
1986 TRACE("Blitter private data couldn't be allocated\n");
1990 /* Set up some starting GL setup */
1992 /* Setup all the devices defaults */
1993 stateblock_init_default_state(This
->stateBlock
);
1995 context
= context_acquire(This
, swapchain
->front_buffer
);
1997 create_dummy_textures(This
);
2001 /* Initialize the current view state */
2002 This
->view_ident
= 1;
2003 This
->contexts
[0]->last_was_rhw
= 0;
2004 glGetIntegerv(GL_MAX_LIGHTS
, &This
->maxConcurrentLights
);
2005 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2007 switch(wined3d_settings
.offscreen_rendering_mode
) {
2009 This
->offscreenBuffer
= GL_COLOR_ATTACHMENT0
;
2012 case ORM_BACKBUFFER
:
2014 if (context_get_current()->aux_buffers
> 0)
2016 TRACE("Using auxilliary buffer for offscreen rendering\n");
2017 This
->offscreenBuffer
= GL_AUX0
;
2019 TRACE("Using back buffer for offscreen rendering\n");
2020 This
->offscreenBuffer
= GL_BACK
;
2025 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This
, This
);
2028 context_release(context
);
2030 /* Clear the screen */
2031 IWineD3DDevice_Clear((IWineD3DDevice
*) This
, 0, NULL
,
2032 WINED3DCLEAR_TARGET
| pPresentationParameters
->EnableAutoDepthStencil
? WINED3DCLEAR_ZBUFFER
| WINED3DCLEAR_STENCIL
: 0,
2035 This
->d3d_initialized
= TRUE
;
2037 if(wined3d_settings
.logo
) {
2038 IWineD3DDeviceImpl_LoadLogo(This
, wined3d_settings
.logo
);
2040 This
->highest_dirty_ps_const
= 0;
2041 This
->highest_dirty_vs_const
= 0;
2045 HeapFree(GetProcessHeap(), 0, This
->render_targets
);
2046 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
2047 This
->NumberOfSwapChains
= 0;
2048 if(This
->palettes
) {
2049 HeapFree(GetProcessHeap(), 0, This
->palettes
[0]);
2050 HeapFree(GetProcessHeap(), 0, This
->palettes
);
2052 This
->NumberOfPalettes
= 0;
2054 IWineD3DSwapChain_Release( (IWineD3DSwapChain
*) swapchain
);
2056 if (This
->stateBlock
)
2058 wined3d_stateblock_decref(This
->stateBlock
);
2059 This
->stateBlock
= NULL
;
2061 if (This
->blit_priv
) {
2062 This
->blitter
->free_private(This
);
2064 if (This
->fragment_priv
) {
2065 This
->frag_pipe
->free_private(This
);
2067 if (This
->shader_priv
) {
2068 This
->shader_backend
->shader_free_private(This
);
2073 static HRESULT WINAPI
IWineD3DDeviceImpl_InitGDI(IWineD3DDevice
*iface
,
2074 WINED3DPRESENT_PARAMETERS
*pPresentationParameters
)
2076 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2077 IWineD3DSwapChainImpl
*swapchain
= NULL
;
2080 /* Setup the implicit swapchain */
2081 TRACE("Creating implicit swapchain\n");
2082 hr
= IWineD3DDeviceParent_CreateSwapChain(This
->device_parent
,
2083 pPresentationParameters
, (IWineD3DSwapChain
**)&swapchain
);
2086 WARN("Failed to create implicit swapchain\n");
2090 This
->NumberOfSwapChains
= 1;
2091 This
->swapchains
= HeapAlloc(GetProcessHeap(), 0, This
->NumberOfSwapChains
* sizeof(*This
->swapchains
));
2092 if (!This
->swapchains
)
2094 ERR("Out of memory!\n");
2097 This
->swapchains
[0] = swapchain
;
2101 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
2105 static HRESULT WINAPI
device_unload_resource(IWineD3DResource
*resource
, void *ctx
)
2107 IWineD3DResource_UnLoad(resource
);
2108 IWineD3DResource_Release(resource
);
2112 static HRESULT WINAPI
IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice
*iface
,
2113 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain
)
2115 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2116 const struct wined3d_gl_info
*gl_info
;
2117 struct IWineD3DSurfaceImpl
*surface
;
2118 struct wined3d_context
*context
;
2121 TRACE("(%p)\n", This
);
2123 if(!This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
2125 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2126 * it was created. Thus make sure a context is active for the glDelete* calls
2128 context
= context_acquire(This
, NULL
);
2129 gl_info
= context
->gl_info
;
2131 if(This
->logo_surface
) IWineD3DSurface_Release(This
->logo_surface
);
2133 /* Unload resources */
2134 IWineD3DDevice_EnumResources(iface
, device_unload_resource
, NULL
);
2136 TRACE("Deleting high order patches\n");
2137 for(i
= 0; i
< PATCHMAP_SIZE
; i
++) {
2138 struct list
*e1
, *e2
;
2139 struct WineD3DRectPatch
*patch
;
2140 LIST_FOR_EACH_SAFE(e1
, e2
, &This
->patches
[i
]) {
2141 patch
= LIST_ENTRY(e1
, struct WineD3DRectPatch
, entry
);
2142 IWineD3DDevice_DeletePatch(iface
, patch
->Handle
);
2146 /* Delete the mouse cursor texture */
2147 if(This
->cursorTexture
) {
2149 glDeleteTextures(1, &This
->cursorTexture
);
2151 This
->cursorTexture
= 0;
2154 for (sampler
= 0; sampler
< MAX_FRAGMENT_SAMPLERS
; ++sampler
) {
2155 IWineD3DDevice_SetTexture(iface
, sampler
, NULL
);
2157 for (sampler
= 0; sampler
< MAX_VERTEX_SAMPLERS
; ++sampler
) {
2158 IWineD3DDevice_SetTexture(iface
, WINED3DVERTEXTEXTURESAMPLER0
+ sampler
, NULL
);
2161 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2162 * private data, it might contain opengl pointers
2164 if(This
->depth_blt_texture
) {
2166 glDeleteTextures(1, &This
->depth_blt_texture
);
2168 This
->depth_blt_texture
= 0;
2170 if (This
->depth_blt_rb
) {
2172 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &This
->depth_blt_rb
);
2174 This
->depth_blt_rb
= 0;
2175 This
->depth_blt_rb_w
= 0;
2176 This
->depth_blt_rb_h
= 0;
2179 /* Release the update stateblock */
2180 if (wined3d_stateblock_decref(This
->updateStateBlock
))
2182 if (This
->updateStateBlock
!= This
->stateBlock
)
2183 FIXME("Something's still holding the update stateblock.\n");
2185 This
->updateStateBlock
= NULL
;
2188 struct wined3d_stateblock
*stateblock
= This
->stateBlock
;
2189 This
->stateBlock
= NULL
;
2191 /* Release the stateblock */
2192 if (wined3d_stateblock_decref(stateblock
))
2193 FIXME("Something's still holding the stateblock.\n");
2196 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2197 This
->blitter
->free_private(This
);
2198 This
->frag_pipe
->free_private(This
);
2199 This
->shader_backend
->shader_free_private(This
);
2201 /* Release the buffers (with sanity checks)*/
2202 if (This
->onscreen_depth_stencil
)
2204 surface
= This
->onscreen_depth_stencil
;
2205 This
->onscreen_depth_stencil
= NULL
;
2206 IWineD3DSurface_Release((IWineD3DSurface
*)surface
);
2209 if (This
->depth_stencil
)
2211 surface
= This
->depth_stencil
;
2213 TRACE("Releasing depth/stencil buffer %p.\n", surface
);
2215 This
->depth_stencil
= NULL
;
2216 if (IWineD3DSurface_Release((IWineD3DSurface
*)surface
)
2217 && surface
!= This
->auto_depth_stencil
)
2219 ERR("Something is still holding a reference to depth/stencil buffer %p.\n", surface
);
2223 if (This
->auto_depth_stencil
)
2225 surface
= This
->auto_depth_stencil
;
2226 This
->auto_depth_stencil
= NULL
;
2227 if (IWineD3DSurface_Release((IWineD3DSurface
*)surface
))
2229 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This
);
2233 for (i
= 1; i
< gl_info
->limits
.buffers
; ++i
)
2235 IWineD3DDevice_SetRenderTarget(iface
, i
, NULL
, FALSE
);
2238 surface
= This
->render_targets
[0];
2239 TRACE("Setting rendertarget 0 to NULL\n");
2240 This
->render_targets
[0] = NULL
;
2241 TRACE("Releasing the render target at %p\n", surface
);
2242 IWineD3DSurface_Release((IWineD3DSurface
*)surface
);
2244 context_release(context
);
2246 for (i
= 0; i
< This
->NumberOfSwapChains
; ++i
)
2248 TRACE("Releasing the implicit swapchain %u.\n", i
);
2249 if (D3DCB_DestroySwapChain((IWineD3DSwapChain
*)This
->swapchains
[i
]) > 0)
2251 FIXME("(%p) Something's still holding the implicit swapchain\n", This
);
2255 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
2256 This
->swapchains
= NULL
;
2257 This
->NumberOfSwapChains
= 0;
2259 for (i
= 0; i
< This
->NumberOfPalettes
; i
++) HeapFree(GetProcessHeap(), 0, This
->palettes
[i
]);
2260 HeapFree(GetProcessHeap(), 0, This
->palettes
);
2261 This
->palettes
= NULL
;
2262 This
->NumberOfPalettes
= 0;
2264 HeapFree(GetProcessHeap(), 0, This
->render_targets
);
2265 This
->render_targets
= NULL
;
2267 This
->d3d_initialized
= FALSE
;
2272 static HRESULT WINAPI
IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice
*iface
, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain
) {
2273 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2276 for (i
= 0; i
< This
->NumberOfSwapChains
; ++i
)
2278 TRACE("Releasing the implicit swapchain %u.\n", i
);
2279 if (D3DCB_DestroySwapChain((IWineD3DSwapChain
*)This
->swapchains
[i
]) > 0)
2281 FIXME("(%p) Something's still holding the implicit swapchain\n", This
);
2285 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
2286 This
->swapchains
= NULL
;
2287 This
->NumberOfSwapChains
= 0;
2291 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2292 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2293 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2295 * There is no way to deactivate thread safety once it is enabled.
2297 static void WINAPI
IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice
*iface
) {
2298 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2300 /*For now just store the flag(needed in case of ddraw) */
2301 This
->createParms
.BehaviorFlags
|= WINED3DCREATE_MULTITHREADED
;
2304 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
,
2305 const WINED3DDISPLAYMODE
* pMode
) {
2307 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2308 const struct wined3d_format
*format
= wined3d_get_format(&This
->adapter
->gl_info
, pMode
->Format
);
2312 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This
, iSwapChain
, pMode
, pMode
->Width
, pMode
->Height
, pMode
->RefreshRate
, debug_d3dformat(pMode
->Format
));
2314 /* Resize the screen even without a window:
2315 * The app could have unset it with SetCooperativeLevel, but not called
2316 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2317 * but we don't have any hwnd
2320 memset(&devmode
, 0, sizeof(devmode
));
2321 devmode
.dmSize
= sizeof(devmode
);
2322 devmode
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
2323 devmode
.dmBitsPerPel
= format
->byte_count
* CHAR_BIT
;
2324 devmode
.dmPelsWidth
= pMode
->Width
;
2325 devmode
.dmPelsHeight
= pMode
->Height
;
2327 devmode
.dmDisplayFrequency
= pMode
->RefreshRate
;
2328 if (pMode
->RefreshRate
)
2329 devmode
.dmFields
|= DM_DISPLAYFREQUENCY
;
2331 /* Only change the mode if necessary */
2332 if (This
->ddraw_width
== pMode
->Width
&& This
->ddraw_height
== pMode
->Height
2333 && This
->ddraw_format
== pMode
->Format
&& !pMode
->RefreshRate
)
2336 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
);
2337 if (ret
!= DISP_CHANGE_SUCCESSFUL
)
2339 if (devmode
.dmDisplayFrequency
)
2341 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2342 devmode
.dmFields
&= ~DM_DISPLAYFREQUENCY
;
2343 devmode
.dmDisplayFrequency
= 0;
2344 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
) != DISP_CHANGE_SUCCESSFUL
;
2346 if(ret
!= DISP_CHANGE_SUCCESSFUL
) {
2347 return WINED3DERR_NOTAVAILABLE
;
2351 /* Store the new values */
2352 This
->ddraw_width
= pMode
->Width
;
2353 This
->ddraw_height
= pMode
->Height
;
2354 This
->ddraw_format
= pMode
->Format
;
2356 /* And finally clip mouse to our screen */
2357 SetRect(&clip_rc
, 0, 0, pMode
->Width
, pMode
->Height
);
2358 ClipCursor(&clip_rc
);
2363 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice
*iface
, struct wined3d
**wined3d
)
2365 IWineD3DDeviceImpl
*device
= (IWineD3DDeviceImpl
*)iface
;
2367 TRACE("iface %p, wined3d %p.\n", iface
, wined3d
);
2369 *wined3d
= device
->wined3d
;
2370 wined3d_incref(*wined3d
);
2372 TRACE("Returning %p.\n", *wined3d
);
2377 static UINT WINAPI
IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice
*iface
) {
2378 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2380 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This
,
2381 (This
->adapter
->TextureRam
/(1024*1024)),
2382 ((This
->adapter
->TextureRam
- This
->adapter
->UsedTextureRam
) / (1024*1024)));
2383 /* return simulated texture memory left */
2384 return (This
->adapter
->TextureRam
- This
->adapter
->UsedTextureRam
);
2388 * Get / Set Stream Source
2390 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice
*iface
, UINT StreamNumber
,
2391 IWineD3DBuffer
*pStreamData
, UINT OffsetInBytes
, UINT Stride
)
2393 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2394 struct wined3d_stream_state
*stream
;
2395 IWineD3DBuffer
*oldSrc
;
2397 TRACE("iface %p, stream_idx %u, buffer %p, offset %u, stride %u.\n",
2398 iface
, StreamNumber
, pStreamData
, OffsetInBytes
, Stride
);
2400 if (StreamNumber
>= MAX_STREAMS
) {
2401 WARN("Stream out of range %d\n", StreamNumber
);
2402 return WINED3DERR_INVALIDCALL
;
2403 } else if(OffsetInBytes
& 0x3) {
2404 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes
);
2405 return WINED3DERR_INVALIDCALL
;
2408 stream
= &This
->updateStateBlock
->state
.streams
[StreamNumber
];
2409 oldSrc
= (IWineD3DBuffer
*)stream
->buffer
;
2411 This
->updateStateBlock
->changed
.streamSource
|= 1 << StreamNumber
;
2413 if (oldSrc
== pStreamData
2414 && stream
->stride
== Stride
2415 && stream
->offset
== OffsetInBytes
)
2417 TRACE("Application is setting the old values over, nothing to do\n");
2421 stream
->buffer
= (struct wined3d_buffer
*)pStreamData
;
2424 stream
->stride
= Stride
;
2425 stream
->offset
= OffsetInBytes
;
2428 /* Handle recording of state blocks */
2429 if (This
->isRecordingState
) {
2430 TRACE("Recording... not performing anything\n");
2431 if (pStreamData
) IWineD3DBuffer_AddRef(pStreamData
);
2432 if (oldSrc
) IWineD3DBuffer_Release(oldSrc
);
2438 InterlockedIncrement(&((struct wined3d_buffer
*)pStreamData
)->bind_count
);
2439 IWineD3DBuffer_AddRef(pStreamData
);
2443 InterlockedDecrement(&((struct wined3d_buffer
*)oldSrc
)->bind_count
);
2444 IWineD3DBuffer_Release(oldSrc
);
2447 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2452 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice
*iface
,
2453 UINT StreamNumber
, IWineD3DBuffer
**pStream
, UINT
*pOffset
, UINT
*pStride
)
2455 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2456 struct wined3d_stream_state
*stream
;
2458 TRACE("iface %p, stream_idx %u, buffer %p, offset %p, stride %p.\n",
2459 iface
, StreamNumber
, pStream
, pOffset
, pStride
);
2461 if (StreamNumber
>= MAX_STREAMS
)
2463 WARN("Stream out of range %d\n", StreamNumber
);
2464 return WINED3DERR_INVALIDCALL
;
2467 stream
= &This
->stateBlock
->state
.streams
[StreamNumber
];
2468 *pStream
= (IWineD3DBuffer
*)stream
->buffer
;
2469 *pStride
= stream
->stride
;
2470 if (pOffset
) *pOffset
= stream
->offset
;
2472 if (*pStream
) IWineD3DBuffer_AddRef(*pStream
);
2477 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT Divider
) {
2478 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2479 struct wined3d_stream_state
*stream
;
2480 UINT old_flags
, oldFreq
;
2482 TRACE("iface %p, stream_idx %u, divider %#x.\n", iface
, StreamNumber
, Divider
);
2484 /* Verify input at least in d3d9 this is invalid. */
2485 if ((Divider
& WINED3DSTREAMSOURCE_INSTANCEDATA
) && (Divider
& WINED3DSTREAMSOURCE_INDEXEDDATA
))
2487 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2488 return WINED3DERR_INVALIDCALL
;
2490 if ((Divider
& WINED3DSTREAMSOURCE_INSTANCEDATA
) && !StreamNumber
)
2492 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2493 return WINED3DERR_INVALIDCALL
;
2497 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2498 return WINED3DERR_INVALIDCALL
;
2501 stream
= &This
->updateStateBlock
->state
.streams
[StreamNumber
];
2502 old_flags
= stream
->flags
;
2503 oldFreq
= stream
->frequency
;
2505 stream
->flags
= Divider
& (WINED3DSTREAMSOURCE_INSTANCEDATA
| WINED3DSTREAMSOURCE_INDEXEDDATA
);
2506 stream
->frequency
= Divider
& 0x7FFFFF;
2508 This
->updateStateBlock
->changed
.streamFreq
|= 1 << StreamNumber
;
2510 if (stream
->frequency
!= oldFreq
|| stream
->flags
!= old_flags
)
2511 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
2516 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT
* Divider
) {
2517 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2518 struct wined3d_stream_state
*stream
;
2520 TRACE("iface %p, stream_idx %u, divider %p.\n", iface
, StreamNumber
, Divider
);
2522 stream
= &This
->updateStateBlock
->state
.streams
[StreamNumber
];
2523 *Divider
= stream
->flags
| stream
->frequency
;
2525 TRACE("Returning %#x.\n", *Divider
);
2531 * Get / Set & Multiply Transform
2533 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE d3dts
, CONST WINED3DMATRIX
* lpmatrix
) {
2534 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2536 /* Most of this routine, comments included copied from ddraw tree initially: */
2537 TRACE("(%p) : Transform State=%s\n", This
, debug_d3dtstype(d3dts
));
2539 /* Handle recording of state blocks */
2540 if (This
->isRecordingState
) {
2541 TRACE("Recording... not performing anything\n");
2542 This
->updateStateBlock
->changed
.transform
[d3dts
>> 5] |= 1 << (d3dts
& 0x1f);
2543 This
->updateStateBlock
->state
.transforms
[d3dts
] = *lpmatrix
;
2548 * If the new matrix is the same as the current one,
2549 * we cut off any further processing. this seems to be a reasonable
2550 * optimization because as was noticed, some apps (warcraft3 for example)
2551 * tend towards setting the same matrix repeatedly for some reason.
2553 * From here on we assume that the new matrix is different, wherever it matters.
2555 if (!memcmp(&This
->stateBlock
->state
.transforms
[d3dts
].u
.m
[0][0], lpmatrix
, sizeof(*lpmatrix
)))
2557 TRACE("The app is setting the same matrix over again\n");
2562 conv_mat(lpmatrix
, &This
->stateBlock
->state
.transforms
[d3dts
].u
.m
[0][0]);
2566 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2567 where ViewMat = Camera space, WorldMat = world space.
2569 In OpenGL, camera and world space is combined into GL_MODELVIEW
2570 matrix. The Projection matrix stay projection matrix.
2573 /* Capture the times we can just ignore the change for now */
2574 if (d3dts
== WINED3DTS_VIEW
) { /* handle the VIEW matrix */
2575 This
->view_ident
= !memcmp(lpmatrix
, identity
, 16 * sizeof(float));
2576 /* Handled by the state manager */
2579 if (d3dts
< WINED3DTS_WORLDMATRIX(This
->adapter
->gl_info
.limits
.blends
))
2580 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TRANSFORM(d3dts
));
2586 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTransform(IWineD3DDevice
*iface
,
2587 WINED3DTRANSFORMSTATETYPE state
, WINED3DMATRIX
*matrix
)
2589 IWineD3DDeviceImpl
*device
= (IWineD3DDeviceImpl
*)iface
;
2591 TRACE("iface %p, state %s, matrix %p.\n", iface
, debug_d3dtstype(state
), matrix
);
2593 *matrix
= device
->stateBlock
->state
.transforms
[state
];
2598 static HRESULT WINAPI
IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, CONST WINED3DMATRIX
* pMatrix
) {
2599 const WINED3DMATRIX
*mat
= NULL
;
2602 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2603 * below means it will be recorded in a state block change, but it
2604 * works regardless where it is recorded.
2605 * If this is found to be wrong, change to StateBlock.
2607 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2608 TRACE("(%p) : For state %s\n", This
, debug_d3dtstype(State
));
2610 if (State
<= HIGHEST_TRANSFORMSTATE
)
2612 mat
= &This
->updateStateBlock
->state
.transforms
[State
];
2616 FIXME("Unhandled transform state!!\n");
2619 multiply_matrix(&temp
, mat
, pMatrix
);
2621 /* Apply change via set transform - will reapply to eg. lights this way */
2622 return IWineD3DDeviceImpl_SetTransform(iface
, State
, &temp
);
2628 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2629 you can reference any indexes you want as long as that number max are enabled at any
2630 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2631 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2632 but when recording, just build a chain pretty much of commands to be replayed. */
2634 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLight(IWineD3DDevice
*iface
, DWORD Index
, CONST WINED3DLIGHT
* pLight
) {
2636 struct wined3d_light_info
*object
= NULL
;
2637 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2640 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2641 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This
, Index
, pLight
, Hi
);
2643 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2647 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2648 return WINED3DERR_INVALIDCALL
;
2651 switch(pLight
->Type
) {
2652 case WINED3DLIGHT_POINT
:
2653 case WINED3DLIGHT_SPOT
:
2654 case WINED3DLIGHT_PARALLELPOINT
:
2655 case WINED3DLIGHT_GLSPOT
:
2656 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2659 if (pLight
->Attenuation0
< 0.0f
|| pLight
->Attenuation1
< 0.0f
|| pLight
->Attenuation2
< 0.0f
)
2661 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2662 return WINED3DERR_INVALIDCALL
;
2666 case WINED3DLIGHT_DIRECTIONAL
:
2667 /* Ignores attenuation */
2671 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2672 return WINED3DERR_INVALIDCALL
;
2675 LIST_FOR_EACH(e
, &This
->updateStateBlock
->state
.light_map
[Hi
])
2677 object
= LIST_ENTRY(e
, struct wined3d_light_info
, entry
);
2678 if(object
->OriginalIndex
== Index
) break;
2683 TRACE("Adding new light\n");
2684 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
2686 ERR("Out of memory error when allocating a light\n");
2687 return E_OUTOFMEMORY
;
2689 list_add_head(&This
->updateStateBlock
->state
.light_map
[Hi
], &object
->entry
);
2690 object
->glIndex
= -1;
2691 object
->OriginalIndex
= Index
;
2694 /* Initialize the object */
2695 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
,
2696 pLight
->Diffuse
.r
, pLight
->Diffuse
.g
, pLight
->Diffuse
.b
, pLight
->Diffuse
.a
,
2697 pLight
->Specular
.r
, pLight
->Specular
.g
, pLight
->Specular
.b
, pLight
->Specular
.a
,
2698 pLight
->Ambient
.r
, pLight
->Ambient
.g
, pLight
->Ambient
.b
, pLight
->Ambient
.a
);
2699 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight
->Position
.x
, pLight
->Position
.y
, pLight
->Position
.z
,
2700 pLight
->Direction
.x
, pLight
->Direction
.y
, pLight
->Direction
.z
);
2701 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight
->Range
, pLight
->Falloff
, pLight
->Theta
, pLight
->Phi
);
2703 /* Save away the information */
2704 object
->OriginalParms
= *pLight
;
2706 switch (pLight
->Type
) {
2707 case WINED3DLIGHT_POINT
:
2709 object
->lightPosn
[0] = pLight
->Position
.x
;
2710 object
->lightPosn
[1] = pLight
->Position
.y
;
2711 object
->lightPosn
[2] = pLight
->Position
.z
;
2712 object
->lightPosn
[3] = 1.0f
;
2713 object
->cutoff
= 180.0f
;
2717 case WINED3DLIGHT_DIRECTIONAL
:
2719 object
->lightPosn
[0] = -pLight
->Direction
.x
;
2720 object
->lightPosn
[1] = -pLight
->Direction
.y
;
2721 object
->lightPosn
[2] = -pLight
->Direction
.z
;
2722 object
->lightPosn
[3] = 0.0f
;
2723 object
->exponent
= 0.0f
;
2724 object
->cutoff
= 180.0f
;
2727 case WINED3DLIGHT_SPOT
:
2729 object
->lightPosn
[0] = pLight
->Position
.x
;
2730 object
->lightPosn
[1] = pLight
->Position
.y
;
2731 object
->lightPosn
[2] = pLight
->Position
.z
;
2732 object
->lightPosn
[3] = 1.0f
;
2735 object
->lightDirn
[0] = pLight
->Direction
.x
;
2736 object
->lightDirn
[1] = pLight
->Direction
.y
;
2737 object
->lightDirn
[2] = pLight
->Direction
.z
;
2738 object
->lightDirn
[3] = 1.0f
;
2741 * opengl-ish and d3d-ish spot lights use too different models for the
2742 * light "intensity" as a function of the angle towards the main light direction,
2743 * so we only can approximate very roughly.
2744 * however spot lights are rather rarely used in games (if ever used at all).
2745 * furthermore if still used, probably nobody pays attention to such details.
2747 if (!pLight
->Falloff
)
2749 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2750 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2751 * will always be 1.0 for both of them, and we don't have to care for the
2752 * rest of the rather complex calculation
2754 object
->exponent
= 0.0f
;
2756 rho
= pLight
->Theta
+ (pLight
->Phi
- pLight
->Theta
)/(2*pLight
->Falloff
);
2757 if (rho
< 0.0001f
) rho
= 0.0001f
;
2758 object
->exponent
= -0.3f
/logf(cosf(rho
/2));
2760 if (object
->exponent
> 128.0f
)
2762 object
->exponent
= 128.0f
;
2764 object
->cutoff
= (float) (pLight
->Phi
*90/M_PI
);
2770 FIXME("Unrecognized light type %d\n", pLight
->Type
);
2773 /* Update the live definitions if the light is currently assigned a glIndex */
2774 if (object
->glIndex
!= -1 && !This
->isRecordingState
) {
2775 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(object
->glIndex
));
2780 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLight(IWineD3DDevice
*iface
, DWORD Index
, WINED3DLIGHT
*pLight
)
2782 struct wined3d_light_info
*lightInfo
= NULL
;
2783 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2784 DWORD Hi
= LIGHTMAP_HASHFUNC(Index
);
2786 TRACE("(%p) : Idx(%d), pLight(%p)\n", This
, Index
, pLight
);
2788 LIST_FOR_EACH(e
, &This
->stateBlock
->state
.light_map
[Hi
])
2790 lightInfo
= LIST_ENTRY(e
, struct wined3d_light_info
, entry
);
2791 if(lightInfo
->OriginalIndex
== Index
) break;
2797 TRACE("Light information requested but light not defined\n");
2798 return WINED3DERR_INVALIDCALL
;
2801 *pLight
= lightInfo
->OriginalParms
;
2806 * Get / Set Light Enable
2807 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2809 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice
*iface
, DWORD Index
, BOOL Enable
)
2811 struct wined3d_light_info
*lightInfo
= NULL
;
2812 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2813 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2815 TRACE("(%p) : Idx(%d), enable? %d\n", This
, Index
, Enable
);
2817 LIST_FOR_EACH(e
, &This
->updateStateBlock
->state
.light_map
[Hi
])
2819 lightInfo
= LIST_ENTRY(e
, struct wined3d_light_info
, entry
);
2820 if(lightInfo
->OriginalIndex
== Index
) break;
2823 TRACE("Found light: %p\n", lightInfo
);
2825 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2828 TRACE("Light enabled requested but light not defined, so defining one!\n");
2829 IWineD3DDeviceImpl_SetLight(iface
, Index
, &WINED3D_default_light
);
2831 /* Search for it again! Should be fairly quick as near head of list */
2832 LIST_FOR_EACH(e
, &This
->updateStateBlock
->state
.light_map
[Hi
])
2834 lightInfo
= LIST_ENTRY(e
, struct wined3d_light_info
, entry
);
2835 if(lightInfo
->OriginalIndex
== Index
) break;
2840 FIXME("Adding default lights has failed dismally\n");
2841 return WINED3DERR_INVALIDCALL
;
2846 if(lightInfo
->glIndex
!= -1) {
2847 if(!This
->isRecordingState
) {
2848 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(lightInfo
->glIndex
));
2851 This
->updateStateBlock
->state
.lights
[lightInfo
->glIndex
] = NULL
;
2852 lightInfo
->glIndex
= -1;
2854 TRACE("Light already disabled, nothing to do\n");
2856 lightInfo
->enabled
= FALSE
;
2858 lightInfo
->enabled
= TRUE
;
2859 if (lightInfo
->glIndex
!= -1) {
2861 TRACE("Nothing to do as light was enabled\n");
2864 /* Find a free gl light */
2865 for (i
= 0; i
< This
->maxConcurrentLights
; ++i
)
2867 if (!This
->updateStateBlock
->state
.lights
[i
])
2869 This
->updateStateBlock
->state
.lights
[i
] = lightInfo
;
2870 lightInfo
->glIndex
= i
;
2874 if(lightInfo
->glIndex
== -1) {
2875 /* Our tests show that Windows returns D3D_OK in this situation, even with
2876 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2877 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2878 * as well for those lights.
2880 * TODO: Test how this affects rendering
2882 WARN("Too many concurrently active lights\n");
2886 /* i == lightInfo->glIndex */
2887 if(!This
->isRecordingState
) {
2888 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(i
));
2896 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice
*iface
, DWORD Index
,BOOL
* pEnable
)
2898 struct wined3d_light_info
*lightInfo
= NULL
;
2899 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2901 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
2902 TRACE("(%p) : for idx(%d)\n", This
, Index
);
2904 LIST_FOR_EACH(e
, &This
->stateBlock
->state
.light_map
[Hi
])
2906 lightInfo
= LIST_ENTRY(e
, struct wined3d_light_info
, entry
);
2907 if(lightInfo
->OriginalIndex
== Index
) break;
2913 TRACE("Light enabled state requested but light not defined\n");
2914 return WINED3DERR_INVALIDCALL
;
2916 /* true is 128 according to SetLightEnable */
2917 *pEnable
= lightInfo
->enabled
? 128 : 0;
2922 * Get / Set Clip Planes
2924 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, CONST
float *pPlane
) {
2925 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2926 TRACE("(%p) : for idx %d, %p\n", This
, Index
, pPlane
);
2928 /* Validate Index */
2929 if (Index
>= This
->adapter
->gl_info
.limits
.clipplanes
)
2931 TRACE("Application has requested clipplane this device doesn't support\n");
2932 return WINED3DERR_INVALIDCALL
;
2935 This
->updateStateBlock
->changed
.clipplane
|= 1 << Index
;
2937 if (This
->updateStateBlock
->state
.clip_planes
[Index
][0] == pPlane
[0]
2938 && This
->updateStateBlock
->state
.clip_planes
[Index
][1] == pPlane
[1]
2939 && This
->updateStateBlock
->state
.clip_planes
[Index
][2] == pPlane
[2]
2940 && This
->updateStateBlock
->state
.clip_planes
[Index
][3] == pPlane
[3])
2942 TRACE("Application is setting old values over, nothing to do\n");
2946 This
->updateStateBlock
->state
.clip_planes
[Index
][0] = pPlane
[0];
2947 This
->updateStateBlock
->state
.clip_planes
[Index
][1] = pPlane
[1];
2948 This
->updateStateBlock
->state
.clip_planes
[Index
][2] = pPlane
[2];
2949 This
->updateStateBlock
->state
.clip_planes
[Index
][3] = pPlane
[3];
2951 /* Handle recording of state blocks */
2952 if (This
->isRecordingState
) {
2953 TRACE("Recording... not performing anything\n");
2957 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_CLIPPLANE(Index
));
2962 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, float *pPlane
) {
2963 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2964 TRACE("(%p) : for idx %d\n", This
, Index
);
2966 /* Validate Index */
2967 if (Index
>= This
->adapter
->gl_info
.limits
.clipplanes
)
2969 TRACE("Application has requested clipplane this device doesn't support\n");
2970 return WINED3DERR_INVALIDCALL
;
2973 pPlane
[0] = (float)This
->stateBlock
->state
.clip_planes
[Index
][0];
2974 pPlane
[1] = (float)This
->stateBlock
->state
.clip_planes
[Index
][1];
2975 pPlane
[2] = (float)This
->stateBlock
->state
.clip_planes
[Index
][2];
2976 pPlane
[3] = (float)This
->stateBlock
->state
.clip_planes
[Index
][3];
2981 * Get / Set Clip Plane Status
2982 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2984 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice
*iface
, CONST WINED3DCLIPSTATUS
* pClipStatus
) {
2985 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2986 FIXME("(%p) : stub\n", This
);
2989 return WINED3DERR_INVALIDCALL
;
2991 This
->updateStateBlock
->state
.clip_status
.ClipUnion
= pClipStatus
->ClipUnion
;
2992 This
->updateStateBlock
->state
.clip_status
.ClipIntersection
= pClipStatus
->ClipIntersection
;
2996 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice
*iface
, WINED3DCLIPSTATUS
* pClipStatus
) {
2997 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2998 FIXME("(%p) : stub\n", This
);
3001 return WINED3DERR_INVALIDCALL
;
3003 pClipStatus
->ClipUnion
= This
->updateStateBlock
->state
.clip_status
.ClipUnion
;
3004 pClipStatus
->ClipIntersection
= This
->updateStateBlock
->state
.clip_status
.ClipIntersection
;
3009 * Get / Set Material
3011 static HRESULT WINAPI
IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice
*iface
, CONST WINED3DMATERIAL
* pMaterial
) {
3012 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3014 This
->updateStateBlock
->changed
.material
= TRUE
;
3015 This
->updateStateBlock
->state
.material
= *pMaterial
;
3017 /* Handle recording of state blocks */
3018 if (This
->isRecordingState
) {
3019 TRACE("Recording... not performing anything\n");
3023 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_MATERIAL
);
3027 static HRESULT WINAPI
IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice
*iface
, WINED3DMATERIAL
* pMaterial
) {
3028 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3029 *pMaterial
= This
->updateStateBlock
->state
.material
;
3030 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This
, pMaterial
->Diffuse
.r
, pMaterial
->Diffuse
.g
,
3031 pMaterial
->Diffuse
.b
, pMaterial
->Diffuse
.a
);
3032 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This
, pMaterial
->Ambient
.r
, pMaterial
->Ambient
.g
,
3033 pMaterial
->Ambient
.b
, pMaterial
->Ambient
.a
);
3034 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This
, pMaterial
->Specular
.r
, pMaterial
->Specular
.g
,
3035 pMaterial
->Specular
.b
, pMaterial
->Specular
.a
);
3036 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This
, pMaterial
->Emissive
.r
, pMaterial
->Emissive
.g
,
3037 pMaterial
->Emissive
.b
, pMaterial
->Emissive
.a
);
3038 TRACE("(%p) : Power (%f)\n", This
, pMaterial
->Power
);
3046 static HRESULT WINAPI
IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice
*iface
,
3047 IWineD3DBuffer
*pIndexData
, enum wined3d_format_id fmt
)
3049 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3050 IWineD3DBuffer
*oldIdxs
;
3052 TRACE("(%p) : Setting to %p\n", This
, pIndexData
);
3053 oldIdxs
= (IWineD3DBuffer
*)This
->updateStateBlock
->state
.index_buffer
;
3055 This
->updateStateBlock
->changed
.indices
= TRUE
;
3056 This
->updateStateBlock
->state
.index_buffer
= (struct wined3d_buffer
*)pIndexData
;
3057 This
->updateStateBlock
->state
.index_format
= fmt
;
3059 /* Handle recording of state blocks */
3060 if (This
->isRecordingState
) {
3061 TRACE("Recording... not performing anything\n");
3062 if(pIndexData
) IWineD3DBuffer_AddRef(pIndexData
);
3063 if(oldIdxs
) IWineD3DBuffer_Release(oldIdxs
);
3067 if(oldIdxs
!= pIndexData
) {
3068 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
3070 InterlockedIncrement(&((struct wined3d_buffer
*)pIndexData
)->bind_count
);
3071 IWineD3DBuffer_AddRef(pIndexData
);
3074 InterlockedDecrement(&((struct wined3d_buffer
*)oldIdxs
)->bind_count
);
3075 IWineD3DBuffer_Release(oldIdxs
);
3082 static HRESULT WINAPI
IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice
*iface
, IWineD3DBuffer
**ppIndexData
)
3084 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3086 *ppIndexData
= (IWineD3DBuffer
*)This
->stateBlock
->state
.index_buffer
;
3088 /* up ref count on ppindexdata */
3090 IWineD3DBuffer_AddRef(*ppIndexData
);
3091 TRACE("(%p) index data set to %p\n", This
, ppIndexData
);
3093 TRACE("(%p) No index data set\n", This
);
3095 TRACE("Returning %p\n", *ppIndexData
);
3100 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3101 static HRESULT WINAPI
IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice
*iface
, INT BaseIndex
) {
3102 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3103 TRACE("(%p)->(%d)\n", This
, BaseIndex
);
3105 if (This
->updateStateBlock
->state
.base_vertex_index
== BaseIndex
)
3107 TRACE("Application is setting the old value over, nothing to do\n");
3111 This
->updateStateBlock
->state
.base_vertex_index
= BaseIndex
;
3113 if (This
->isRecordingState
) {
3114 TRACE("Recording... not performing anything\n");
3117 /* The base vertex index affects the stream sources */
3118 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
3122 static HRESULT WINAPI
IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice
*iface
, INT
* base_index
) {
3123 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3124 TRACE("(%p) : base_index %p\n", This
, base_index
);
3126 *base_index
= This
->stateBlock
->state
.base_vertex_index
;
3128 TRACE("Returning %u\n", *base_index
);
3134 * Get / Set Viewports
3136 static HRESULT WINAPI
IWineD3DDeviceImpl_SetViewport(IWineD3DDevice
*iface
, CONST WINED3DVIEWPORT
* pViewport
) {
3137 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3139 TRACE("(%p)\n", This
);
3140 This
->updateStateBlock
->changed
.viewport
= TRUE
;
3141 This
->updateStateBlock
->state
.viewport
= *pViewport
;
3143 /* Handle recording of state blocks */
3144 if (This
->isRecordingState
) {
3145 TRACE("Recording... not performing anything\n");
3149 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This
,
3150 pViewport
->X
, pViewport
->Y
, pViewport
->Width
, pViewport
->Height
, pViewport
->MinZ
, pViewport
->MaxZ
);
3152 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VIEWPORT
);
3157 static HRESULT WINAPI
IWineD3DDeviceImpl_GetViewport(IWineD3DDevice
*iface
, WINED3DVIEWPORT
* pViewport
) {
3158 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3159 TRACE("(%p)\n", This
);
3160 *pViewport
= This
->stateBlock
->state
.viewport
;
3164 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice
*iface
,
3165 WINED3DRENDERSTATETYPE State
, DWORD Value
)
3167 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3168 DWORD oldValue
= This
->stateBlock
->state
.render_states
[State
];
3170 TRACE("iface %p, state %s (%#x), value %#x.\n", iface
, debug_d3drenderstate(State
), State
, Value
);
3172 This
->updateStateBlock
->changed
.renderState
[State
>> 5] |= 1 << (State
& 0x1f);
3173 This
->updateStateBlock
->state
.render_states
[State
] = Value
;
3175 /* Handle recording of state blocks */
3176 if (This
->isRecordingState
) {
3177 TRACE("Recording... not performing anything\n");
3181 /* Compared here and not before the assignment to allow proper stateblock recording */
3182 if(Value
== oldValue
) {
3183 TRACE("Application is setting the old value over, nothing to do\n");
3185 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(State
));
3191 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice
*iface
,
3192 WINED3DRENDERSTATETYPE State
, DWORD
*pValue
)
3194 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3196 TRACE("iface %p, state %s (%#x), value %p.\n", iface
, debug_d3drenderstate(State
), State
, pValue
);
3198 *pValue
= This
->stateBlock
->state
.render_states
[State
];
3203 * Get / Set Sampler States
3204 * TODO: Verify against dx9 definitions
3207 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD Value
) {
3208 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3211 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3212 This
, Sampler
, debug_d3dsamplerstate(Type
), Type
, Value
);
3214 if (Sampler
>= WINED3DVERTEXTEXTURESAMPLER0
&& Sampler
<= WINED3DVERTEXTEXTURESAMPLER3
) {
3215 Sampler
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
3218 if (Sampler
>= sizeof(This
->stateBlock
->state
.sampler_states
) / sizeof(*This
->stateBlock
->state
.sampler_states
))
3220 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler
);
3221 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
3224 oldValue
= This
->stateBlock
->state
.sampler_states
[Sampler
][Type
];
3225 This
->updateStateBlock
->state
.sampler_states
[Sampler
][Type
] = Value
;
3226 This
->updateStateBlock
->changed
.samplerState
[Sampler
] |= 1 << Type
;
3228 /* Handle recording of state blocks */
3229 if (This
->isRecordingState
) {
3230 TRACE("Recording... not performing anything\n");
3234 if(oldValue
== Value
) {
3235 TRACE("Application is setting the old value over, nothing to do\n");
3239 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(Sampler
));
3244 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD
* Value
) {
3245 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3247 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3248 This
, Sampler
, debug_d3dsamplerstate(Type
), Type
);
3250 if (Sampler
>= WINED3DVERTEXTEXTURESAMPLER0
&& Sampler
<= WINED3DVERTEXTEXTURESAMPLER3
) {
3251 Sampler
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
3254 if (Sampler
>= sizeof(This
->stateBlock
->state
.sampler_states
) / sizeof(*This
->stateBlock
->state
.sampler_states
))
3256 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler
);
3257 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
3259 *Value
= This
->stateBlock
->state
.sampler_states
[Sampler
][Type
];
3260 TRACE("(%p) : Returning %#x\n", This
, *Value
);
3265 static HRESULT WINAPI
IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice
*iface
, CONST RECT
* pRect
) {
3266 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3268 This
->updateStateBlock
->changed
.scissorRect
= TRUE
;
3269 if (EqualRect(&This
->updateStateBlock
->state
.scissor_rect
, pRect
))
3271 TRACE("App is setting the old scissor rectangle over, nothing to do.\n");
3274 CopyRect(&This
->updateStateBlock
->state
.scissor_rect
, pRect
);
3276 if(This
->isRecordingState
) {
3277 TRACE("Recording... not performing anything\n");
3281 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SCISSORRECT
);
3286 static HRESULT WINAPI
IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice
*iface
, RECT
* pRect
) {
3287 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3289 *pRect
= This
->updateStateBlock
->state
.scissor_rect
;
3290 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This
, pRect
->left
, pRect
->top
, pRect
->right
, pRect
->bottom
);
3294 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice
*iface
,
3295 struct wined3d_vertex_declaration
*pDecl
)
3297 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
3298 struct wined3d_vertex_declaration
*oldDecl
= This
->updateStateBlock
->state
.vertex_declaration
;
3300 TRACE("iface %p, declaration %p.\n", iface
, pDecl
);
3303 wined3d_vertex_declaration_incref(pDecl
);
3305 wined3d_vertex_declaration_decref(oldDecl
);
3307 This
->updateStateBlock
->state
.vertex_declaration
= pDecl
;
3308 This
->updateStateBlock
->changed
.vertexDecl
= TRUE
;
3310 if (This
->isRecordingState
) {
3311 TRACE("Recording... not performing anything\n");
3313 } else if(pDecl
== oldDecl
) {
3314 /* Checked after the assignment to allow proper stateblock recording */
3315 TRACE("Application is setting the old declaration over, nothing to do\n");
3319 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
3323 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice
*iface
,
3324 struct wined3d_vertex_declaration
**ppDecl
)
3326 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3328 TRACE("iface %p, declaration %p.\n", iface
, ppDecl
);
3330 *ppDecl
= This
->stateBlock
->state
.vertex_declaration
;
3332 wined3d_vertex_declaration_incref(*ppDecl
);
3337 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
*pShader
)
3339 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3340 IWineD3DVertexShader
*oldShader
= (IWineD3DVertexShader
*)This
->updateStateBlock
->state
.vertex_shader
;
3342 This
->updateStateBlock
->state
.vertex_shader
= (IWineD3DVertexShaderImpl
*)pShader
;
3343 This
->updateStateBlock
->changed
.vertexShader
= TRUE
;
3345 if (This
->isRecordingState
) {
3346 if(pShader
) IWineD3DVertexShader_AddRef(pShader
);
3347 if(oldShader
) IWineD3DVertexShader_Release(oldShader
);
3348 TRACE("Recording... not performing anything\n");
3350 } else if(oldShader
== pShader
) {
3351 /* Checked here to allow proper stateblock recording */
3352 TRACE("App is setting the old shader over, nothing to do\n");
3356 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
3357 if(pShader
) IWineD3DVertexShader_AddRef(pShader
);
3358 if(oldShader
) IWineD3DVertexShader_Release(oldShader
);
3360 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VSHADER
);
3365 static IWineD3DVertexShader
* WINAPI
IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice
*iface
)
3367 IWineD3DDeviceImpl
*device
= (IWineD3DDeviceImpl
*)iface
;
3368 IWineD3DVertexShader
*shader
;
3370 TRACE("iface %p.\n", iface
);
3372 shader
= (IWineD3DVertexShader
*)device
->stateBlock
->state
.vertex_shader
;
3373 if (shader
) IWineD3DVertexShader_AddRef(shader
);
3375 TRACE("Returning %p.\n", shader
);
3379 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantB(
3380 IWineD3DDevice
*iface
,
3382 CONST BOOL
*srcData
,
3385 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3386 unsigned int i
, cnt
= min(count
, MAX_CONST_B
- start
);
3388 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3389 iface
, srcData
, start
, count
);
3391 if (!srcData
|| start
>= MAX_CONST_B
) return WINED3DERR_INVALIDCALL
;
3393 memcpy(&This
->updateStateBlock
->state
.vs_consts_b
[start
], srcData
, cnt
* sizeof(BOOL
));
3394 for (i
= 0; i
< cnt
; i
++)
3395 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
3397 for (i
= start
; i
< cnt
+ start
; ++i
) {
3398 This
->updateStateBlock
->changed
.vertexShaderConstantsB
|= (1 << i
);
3401 if (!This
->isRecordingState
) IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3406 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantB(
3407 IWineD3DDevice
*iface
,
3412 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3413 int cnt
= min(count
, MAX_CONST_B
- start
);
3415 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3416 iface
, dstData
, start
, count
);
3418 if (!dstData
|| cnt
< 0)
3419 return WINED3DERR_INVALIDCALL
;
3421 memcpy(dstData
, &This
->stateBlock
->state
.vs_consts_b
[start
], cnt
* sizeof(BOOL
));
3425 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantI(
3426 IWineD3DDevice
*iface
,
3431 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3432 unsigned int i
, cnt
= min(count
, MAX_CONST_I
- start
);
3434 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3435 iface
, srcData
, start
, count
);
3437 if (!srcData
|| start
>= MAX_CONST_I
) return WINED3DERR_INVALIDCALL
;
3439 memcpy(&This
->updateStateBlock
->state
.vs_consts_i
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
3440 for (i
= 0; i
< cnt
; i
++)
3441 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
3442 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3444 for (i
= start
; i
< cnt
+ start
; ++i
) {
3445 This
->updateStateBlock
->changed
.vertexShaderConstantsI
|= (1 << i
);
3448 if (!This
->isRecordingState
) IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3453 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantI(
3454 IWineD3DDevice
*iface
,
3459 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3460 int cnt
= min(count
, MAX_CONST_I
- start
);
3462 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3463 iface
, dstData
, start
, count
);
3465 if (!dstData
|| ((signed int)MAX_CONST_I
- (signed int)start
) <= 0)
3466 return WINED3DERR_INVALIDCALL
;
3468 memcpy(dstData
, &This
->stateBlock
->state
.vs_consts_i
[start
* 4], cnt
* sizeof(int) * 4);
3472 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantF(
3473 IWineD3DDevice
*iface
,
3475 CONST
float *srcData
,
3478 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3481 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3482 iface
, srcData
, start
, count
);
3484 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3485 if (!srcData
|| start
+ count
> This
->d3d_vshader_constantF
|| start
> This
->d3d_vshader_constantF
)
3486 return WINED3DERR_INVALIDCALL
;
3488 memcpy(&This
->updateStateBlock
->state
.vs_consts_f
[start
* 4], srcData
, count
* sizeof(float) * 4);
3490 for (i
= 0; i
< count
; i
++)
3491 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
3492 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3495 if (!This
->isRecordingState
)
3497 This
->shader_backend
->shader_update_float_vertex_constants(This
, start
, count
);
3498 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3501 memset(This
->updateStateBlock
->changed
.vertexShaderConstantsF
+ start
, 1,
3502 sizeof(*This
->updateStateBlock
->changed
.vertexShaderConstantsF
) * count
);
3507 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantF(
3508 IWineD3DDevice
*iface
,
3513 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3514 int cnt
= min(count
, This
->d3d_vshader_constantF
- start
);
3516 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3517 iface
, dstData
, start
, count
);
3519 if (!dstData
|| cnt
< 0)
3520 return WINED3DERR_INVALIDCALL
;
3522 memcpy(dstData
, &This
->stateBlock
->state
.vs_consts_f
[start
* 4], cnt
* sizeof(float) * 4);
3526 static inline void markTextureStagesDirty(IWineD3DDeviceImpl
*This
, DWORD stage
) {
3528 for(i
= 0; i
<= WINED3D_HIGHEST_TEXTURE_STATE
; ++i
)
3530 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, i
));
3534 static void device_map_stage(IWineD3DDeviceImpl
*This
, DWORD stage
, DWORD unit
)
3536 DWORD i
= This
->rev_tex_unit_map
[unit
];
3537 DWORD j
= This
->texUnitMap
[stage
];
3539 This
->texUnitMap
[stage
] = unit
;
3540 if (i
!= WINED3D_UNMAPPED_STAGE
&& i
!= stage
)
3542 This
->texUnitMap
[i
] = WINED3D_UNMAPPED_STAGE
;
3545 This
->rev_tex_unit_map
[unit
] = stage
;
3546 if (j
!= WINED3D_UNMAPPED_STAGE
&& j
!= unit
)
3548 This
->rev_tex_unit_map
[j
] = WINED3D_UNMAPPED_STAGE
;
3552 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl
*This
) {
3555 This
->fixed_function_usage_map
= 0;
3556 for (i
= 0; i
< MAX_TEXTURES
; ++i
)
3558 const struct wined3d_state
*state
= &This
->stateBlock
->state
;
3559 WINED3DTEXTUREOP color_op
= state
->texture_states
[i
][WINED3DTSS_COLOROP
];
3560 WINED3DTEXTUREOP alpha_op
= state
->texture_states
[i
][WINED3DTSS_ALPHAOP
];
3561 DWORD color_arg1
= state
->texture_states
[i
][WINED3DTSS_COLORARG1
] & WINED3DTA_SELECTMASK
;
3562 DWORD color_arg2
= state
->texture_states
[i
][WINED3DTSS_COLORARG2
] & WINED3DTA_SELECTMASK
;
3563 DWORD color_arg3
= state
->texture_states
[i
][WINED3DTSS_COLORARG0
] & WINED3DTA_SELECTMASK
;
3564 DWORD alpha_arg1
= state
->texture_states
[i
][WINED3DTSS_ALPHAARG1
] & WINED3DTA_SELECTMASK
;
3565 DWORD alpha_arg2
= state
->texture_states
[i
][WINED3DTSS_ALPHAARG2
] & WINED3DTA_SELECTMASK
;
3566 DWORD alpha_arg3
= state
->texture_states
[i
][WINED3DTSS_ALPHAARG0
] & WINED3DTA_SELECTMASK
;
3568 if (color_op
== WINED3DTOP_DISABLE
) {
3569 /* Not used, and disable higher stages */
3573 if (((color_arg1
== WINED3DTA_TEXTURE
) && color_op
!= WINED3DTOP_SELECTARG2
)
3574 || ((color_arg2
== WINED3DTA_TEXTURE
) && color_op
!= WINED3DTOP_SELECTARG1
)
3575 || ((color_arg3
== WINED3DTA_TEXTURE
) && (color_op
== WINED3DTOP_MULTIPLYADD
|| color_op
== WINED3DTOP_LERP
))
3576 || ((alpha_arg1
== WINED3DTA_TEXTURE
) && alpha_op
!= WINED3DTOP_SELECTARG2
)
3577 || ((alpha_arg2
== WINED3DTA_TEXTURE
) && alpha_op
!= WINED3DTOP_SELECTARG1
)
3578 || ((alpha_arg3
== WINED3DTA_TEXTURE
) && (alpha_op
== WINED3DTOP_MULTIPLYADD
|| alpha_op
== WINED3DTOP_LERP
))) {
3579 This
->fixed_function_usage_map
|= (1 << i
);
3582 if ((color_op
== WINED3DTOP_BUMPENVMAP
|| color_op
== WINED3DTOP_BUMPENVMAPLUMINANCE
) && i
< MAX_TEXTURES
- 1) {
3583 This
->fixed_function_usage_map
|= (1 << (i
+ 1));
3588 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl
*This
, const struct wined3d_gl_info
*gl_info
)
3590 unsigned int i
, tex
;
3593 device_update_fixed_function_usage_map(This
);
3594 ffu_map
= This
->fixed_function_usage_map
;
3596 if (This
->max_ffp_textures
== gl_info
->limits
.texture_stages
3597 || This
->stateBlock
->state
.lowest_disabled_stage
<= This
->max_ffp_textures
)
3599 for (i
= 0; ffu_map
; ffu_map
>>= 1, ++i
)
3601 if (!(ffu_map
& 1)) continue;
3603 if (This
->texUnitMap
[i
] != i
) {
3604 device_map_stage(This
, i
, i
);
3605 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3606 markTextureStagesDirty(This
, i
);
3612 /* Now work out the mapping */
3614 for (i
= 0; ffu_map
; ffu_map
>>= 1, ++i
)
3616 if (!(ffu_map
& 1)) continue;
3618 if (This
->texUnitMap
[i
] != tex
) {
3619 device_map_stage(This
, i
, tex
);
3620 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3621 markTextureStagesDirty(This
, i
);
3628 static void device_map_psamplers(IWineD3DDeviceImpl
*This
, const struct wined3d_gl_info
*gl_info
)
3630 const WINED3DSAMPLER_TEXTURE_TYPE
*sampler_type
=
3631 This
->stateBlock
->state
.pixel_shader
->baseShader
.reg_maps
.sampler_type
;
3634 for (i
= 0; i
< MAX_FRAGMENT_SAMPLERS
; ++i
) {
3635 if (sampler_type
[i
] && This
->texUnitMap
[i
] != i
)
3637 device_map_stage(This
, i
, i
);
3638 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
3639 if (i
< gl_info
->limits
.texture_stages
)
3641 markTextureStagesDirty(This
, i
);
3647 static BOOL
device_unit_free_for_vs(IWineD3DDeviceImpl
*This
, const WINED3DSAMPLER_TEXTURE_TYPE
*pshader_sampler_tokens
,
3648 const WINED3DSAMPLER_TEXTURE_TYPE
*vshader_sampler_tokens
, DWORD unit
)
3650 DWORD current_mapping
= This
->rev_tex_unit_map
[unit
];
3652 /* Not currently used */
3653 if (current_mapping
== WINED3D_UNMAPPED_STAGE
) return TRUE
;
3655 if (current_mapping
< MAX_FRAGMENT_SAMPLERS
) {
3656 /* Used by a fragment sampler */
3658 if (!pshader_sampler_tokens
) {
3659 /* No pixel shader, check fixed function */
3660 return current_mapping
>= MAX_TEXTURES
|| !(This
->fixed_function_usage_map
& (1 << current_mapping
));
3663 /* Pixel shader, check the shader's sampler map */
3664 return !pshader_sampler_tokens
[current_mapping
];
3667 /* Used by a vertex sampler */
3668 return !vshader_sampler_tokens
[current_mapping
- MAX_FRAGMENT_SAMPLERS
];
3671 static void device_map_vsamplers(IWineD3DDeviceImpl
*This
, BOOL ps
, const struct wined3d_gl_info
*gl_info
)
3673 const WINED3DSAMPLER_TEXTURE_TYPE
*vshader_sampler_type
=
3674 This
->stateBlock
->state
.vertex_shader
->baseShader
.reg_maps
.sampler_type
;
3675 const WINED3DSAMPLER_TEXTURE_TYPE
*pshader_sampler_type
= NULL
;
3676 int start
= min(MAX_COMBINED_SAMPLERS
, gl_info
->limits
.combined_samplers
) - 1;
3681 IWineD3DPixelShaderImpl
*pshader
= This
->stateBlock
->state
.pixel_shader
;
3683 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3684 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3685 pshader_sampler_type
= pshader
->baseShader
.reg_maps
.sampler_type
;
3688 for (i
= 0; i
< MAX_VERTEX_SAMPLERS
; ++i
) {
3689 DWORD vsampler_idx
= i
+ MAX_FRAGMENT_SAMPLERS
;
3690 if (vshader_sampler_type
[i
])
3692 if (This
->texUnitMap
[vsampler_idx
] != WINED3D_UNMAPPED_STAGE
)
3694 /* Already mapped somewhere */
3698 while (start
>= 0) {
3699 if (device_unit_free_for_vs(This
, pshader_sampler_type
, vshader_sampler_type
, start
))
3701 device_map_stage(This
, vsampler_idx
, start
);
3702 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(vsampler_idx
));
3714 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl
*This
)
3716 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
3717 const struct wined3d_state
*state
= &This
->stateBlock
->state
;
3718 BOOL vs
= use_vs(state
);
3719 BOOL ps
= use_ps(state
);
3722 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3723 * that would be really messy and require shader recompilation
3724 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3725 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3727 if (ps
) device_map_psamplers(This
, gl_info
);
3728 else device_map_fixed_function_samplers(This
, gl_info
);
3730 if (vs
) device_map_vsamplers(This
, ps
, gl_info
);
3733 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
*pShader
)
3735 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3736 IWineD3DPixelShader
*oldShader
= (IWineD3DPixelShader
*)This
->updateStateBlock
->state
.pixel_shader
;
3737 This
->updateStateBlock
->state
.pixel_shader
= (IWineD3DPixelShaderImpl
*)pShader
;
3738 This
->updateStateBlock
->changed
.pixelShader
= TRUE
;
3740 /* Handle recording of state blocks */
3741 if (This
->isRecordingState
) {
3742 TRACE("Recording... not performing anything\n");
3745 if (This
->isRecordingState
) {
3746 TRACE("Recording... not performing anything\n");
3747 if(pShader
) IWineD3DPixelShader_AddRef(pShader
);
3748 if(oldShader
) IWineD3DPixelShader_Release(oldShader
);
3752 if(pShader
== oldShader
) {
3753 TRACE("App is setting the old pixel shader over, nothing to do\n");
3757 if(pShader
) IWineD3DPixelShader_AddRef(pShader
);
3758 if(oldShader
) IWineD3DPixelShader_Release(oldShader
);
3760 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
3761 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADER
);
3766 static IWineD3DPixelShader
* WINAPI
IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice
*iface
)
3768 IWineD3DDeviceImpl
*device
= (IWineD3DDeviceImpl
*)iface
;
3769 IWineD3DPixelShader
*shader
;
3771 TRACE("iface %p.\n", iface
);
3773 shader
= (IWineD3DPixelShader
*)device
->stateBlock
->state
.pixel_shader
;
3774 if (shader
) IWineD3DPixelShader_AddRef(shader
);
3776 TRACE("Returning %p.\n", shader
);
3780 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantB(
3781 IWineD3DDevice
*iface
,
3783 CONST BOOL
*srcData
,
3786 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3787 unsigned int i
, cnt
= min(count
, MAX_CONST_B
- start
);
3789 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3790 iface
, srcData
, start
, count
);
3792 if (!srcData
|| start
>= MAX_CONST_B
) return WINED3DERR_INVALIDCALL
;
3794 memcpy(&This
->updateStateBlock
->state
.ps_consts_b
[start
], srcData
, cnt
* sizeof(BOOL
));
3795 for (i
= 0; i
< cnt
; i
++)
3796 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
3798 for (i
= start
; i
< cnt
+ start
; ++i
) {
3799 This
->updateStateBlock
->changed
.pixelShaderConstantsB
|= (1 << i
);
3802 if (!This
->isRecordingState
) IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3807 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantB(
3808 IWineD3DDevice
*iface
,
3813 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3814 int cnt
= min(count
, MAX_CONST_B
- start
);
3816 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3817 iface
, dstData
, start
, count
);
3819 if (!dstData
|| cnt
< 0)
3820 return WINED3DERR_INVALIDCALL
;
3822 memcpy(dstData
, &This
->stateBlock
->state
.ps_consts_b
[start
], cnt
* sizeof(BOOL
));
3826 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantI(
3827 IWineD3DDevice
*iface
,
3832 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3833 unsigned int i
, cnt
= min(count
, MAX_CONST_I
- start
);
3835 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3836 iface
, srcData
, start
, count
);
3838 if (!srcData
|| start
>= MAX_CONST_I
) return WINED3DERR_INVALIDCALL
;
3840 memcpy(&This
->updateStateBlock
->state
.ps_consts_i
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
3841 for (i
= 0; i
< cnt
; i
++)
3842 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
3843 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3845 for (i
= start
; i
< cnt
+ start
; ++i
) {
3846 This
->updateStateBlock
->changed
.pixelShaderConstantsI
|= (1 << i
);
3849 if (!This
->isRecordingState
) IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3854 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantI(
3855 IWineD3DDevice
*iface
,
3860 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3861 int cnt
= min(count
, MAX_CONST_I
- start
);
3863 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3864 iface
, dstData
, start
, count
);
3866 if (!dstData
|| cnt
< 0)
3867 return WINED3DERR_INVALIDCALL
;
3869 memcpy(dstData
, &This
->stateBlock
->state
.ps_consts_i
[start
* 4], cnt
* sizeof(int) * 4);
3873 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantF(
3874 IWineD3DDevice
*iface
,
3876 CONST
float *srcData
,
3879 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3882 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3883 iface
, srcData
, start
, count
);
3885 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3886 if (!srcData
|| start
+ count
> This
->d3d_pshader_constantF
|| start
> This
->d3d_pshader_constantF
)
3887 return WINED3DERR_INVALIDCALL
;
3889 memcpy(&This
->updateStateBlock
->state
.ps_consts_f
[start
* 4], srcData
, count
* sizeof(float) * 4);
3891 for (i
= 0; i
< count
; i
++)
3892 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
3893 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
3896 if (!This
->isRecordingState
)
3898 This
->shader_backend
->shader_update_float_pixel_constants(This
, start
, count
);
3899 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
3902 memset(This
->updateStateBlock
->changed
.pixelShaderConstantsF
+ start
, 1,
3903 sizeof(*This
->updateStateBlock
->changed
.pixelShaderConstantsF
) * count
);
3908 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantF(
3909 IWineD3DDevice
*iface
,
3914 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3915 int cnt
= min(count
, This
->d3d_pshader_constantF
- start
);
3917 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3918 iface
, dstData
, start
, count
);
3920 if (!dstData
|| cnt
< 0)
3921 return WINED3DERR_INVALIDCALL
;
3923 memcpy(dstData
, &This
->stateBlock
->state
.ps_consts_f
[start
* 4], cnt
* sizeof(float) * 4);
3927 /* Context activation is done by the caller. */
3928 /* Do not call while under the GL lock. */
3929 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3930 static HRESULT
process_vertices_strided(IWineD3DDeviceImpl
*This
, DWORD dwDestIndex
, DWORD dwCount
,
3931 const struct wined3d_stream_info
*stream_info
, struct wined3d_buffer
*dest
, DWORD flags
,
3934 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
3935 char *dest_ptr
, *dest_conv
= NULL
, *dest_conv_addr
= NULL
;
3938 WINED3DMATRIX mat
, proj_mat
, view_mat
, world_mat
;
3942 if (stream_info
->use_map
& (1 << WINED3D_FFP_NORMAL
))
3944 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3947 if (!(stream_info
->use_map
& (1 << WINED3D_FFP_POSITION
)))
3949 ERR("Source has no position mask\n");
3950 return WINED3DERR_INVALIDCALL
;
3953 if (!dest
->resource
.allocatedMemory
)
3954 buffer_get_sysmem(dest
, gl_info
);
3956 /* Get a pointer into the destination vbo(create one if none exists) and
3957 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3959 if (!dest
->buffer_object
&& gl_info
->supported
[ARB_VERTEX_BUFFER_OBJECT
])
3961 dest
->flags
|= WINED3D_BUFFER_CREATEBO
;
3962 IWineD3DBuffer_PreLoad((IWineD3DBuffer
*)dest
);
3965 if (dest
->buffer_object
)
3967 unsigned char extrabytes
= 0;
3968 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3969 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3970 * this may write 4 extra bytes beyond the area that should be written
3972 if(DestFVF
== WINED3DFVF_XYZ
) extrabytes
= 4;
3973 dest_conv_addr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwCount
* get_flexible_vertex_size(DestFVF
) + extrabytes
);
3974 if(!dest_conv_addr
) {
3975 ERR("Out of memory\n");
3976 /* Continue without storing converted vertices */
3978 dest_conv
= dest_conv_addr
;
3981 if (This
->stateBlock
->state
.render_states
[WINED3DRS_CLIPPING
])
3983 static BOOL warned
= FALSE
;
3985 * The clipping code is not quite correct. Some things need
3986 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3987 * so disable clipping for now.
3988 * (The graphics in Half-Life are broken, and my processvertices
3989 * test crashes with IDirect3DDevice3)
3995 FIXME("Clipping is broken and disabled for now\n");
3997 } else doClip
= FALSE
;
3998 dest_ptr
= ((char *)buffer_get_sysmem(dest
, gl_info
)) + dwDestIndex
* get_flexible_vertex_size(DestFVF
);
4000 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
4003 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
4004 WINED3DTS_PROJECTION
,
4006 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
4007 WINED3DTS_WORLDMATRIX(0),
4010 TRACE("View mat:\n");
4011 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
);
4012 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
);
4013 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
);
4014 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
);
4016 TRACE("Proj mat:\n");
4017 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
);
4018 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
);
4019 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
);
4020 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
);
4022 TRACE("World mat:\n");
4023 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
);
4024 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
);
4025 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
);
4026 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
);
4028 /* Get the viewport */
4029 IWineD3DDevice_GetViewport( (IWineD3DDevice
*) This
, &vp
);
4030 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4031 vp
.X
, vp
.Y
, vp
.Width
, vp
.Height
, vp
.MinZ
, vp
.MaxZ
);
4033 multiply_matrix(&mat
,&view_mat
,&world_mat
);
4034 multiply_matrix(&mat
,&proj_mat
,&mat
);
4036 numTextures
= (DestFVF
& WINED3DFVF_TEXCOUNT_MASK
) >> WINED3DFVF_TEXCOUNT_SHIFT
;
4038 for (i
= 0; i
< dwCount
; i
+= 1) {
4039 unsigned int tex_index
;
4041 if ( ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZ
) ||
4042 ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) ) {
4043 /* The position first */
4044 const struct wined3d_stream_info_element
*element
= &stream_info
->elements
[WINED3D_FFP_POSITION
];
4045 const float *p
= (const float *)(element
->data
+ i
* element
->stride
);
4047 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p
[0], p
[1], p
[2]);
4049 /* Multiplication with world, view and projection matrix */
4050 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
);
4051 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
);
4052 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
);
4053 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
);
4055 TRACE("x=%f y=%f z=%f rhw=%f\n", x
, y
, z
, rhw
);
4057 /* WARNING: The following things are taken from d3d7 and were not yet checked
4058 * against d3d8 or d3d9!
4061 /* Clipping conditions: From msdn
4063 * A vertex is clipped if it does not match the following requirements
4067 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4069 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4070 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4075 ( (-rhw
-eps
< x
) && (-rhw
-eps
< y
) && ( -eps
< z
) &&
4076 (x
<= rhw
+ eps
) && (y
<= rhw
+ eps
) && (z
<= rhw
+ eps
) &&
4079 /* "Normal" viewport transformation (not clipped)
4080 * 1) The values are divided by rhw
4081 * 2) The y axis is negative, so multiply it with -1
4082 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4083 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4084 * 4) Multiply x with Width/2 and add Width/2
4085 * 5) The same for the height
4086 * 6) Add the viewpoint X and Y to the 2D coordinates and
4087 * The minimum Z value to z
4088 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4090 * Well, basically it's simply a linear transformation into viewport
4102 z
*= vp
.MaxZ
- vp
.MinZ
;
4104 x
+= vp
.Width
/ 2 + vp
.X
;
4105 y
+= vp
.Height
/ 2 + vp
.Y
;
4110 /* That vertex got clipped
4111 * Contrary to OpenGL it is not dropped completely, it just
4112 * undergoes a different calculation.
4114 TRACE("Vertex got clipped\n");
4121 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4122 * outside of the main vertex buffer memory. That needs some more
4127 TRACE("Writing (%f %f %f) %f\n", x
, y
, z
, rhw
);
4130 ( (float *) dest_ptr
)[0] = x
;
4131 ( (float *) dest_ptr
)[1] = y
;
4132 ( (float *) dest_ptr
)[2] = z
;
4133 ( (float *) dest_ptr
)[3] = rhw
; /* SIC, see ddraw test! */
4135 dest_ptr
+= 3 * sizeof(float);
4137 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
4138 dest_ptr
+= sizeof(float);
4143 ( (float *) dest_conv
)[0] = x
* w
;
4144 ( (float *) dest_conv
)[1] = y
* w
;
4145 ( (float *) dest_conv
)[2] = z
* w
;
4146 ( (float *) dest_conv
)[3] = w
;
4148 dest_conv
+= 3 * sizeof(float);
4150 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
4151 dest_conv
+= sizeof(float);
4155 if (DestFVF
& WINED3DFVF_PSIZE
) {
4156 dest_ptr
+= sizeof(DWORD
);
4157 if(dest_conv
) dest_conv
+= sizeof(DWORD
);
4159 if (DestFVF
& WINED3DFVF_NORMAL
) {
4160 const struct wined3d_stream_info_element
*element
= &stream_info
->elements
[WINED3D_FFP_NORMAL
];
4161 const float *normal
= (const float *)(element
->data
+ i
* element
->stride
);
4162 /* AFAIK this should go into the lighting information */
4163 FIXME("Didn't expect the destination to have a normal\n");
4164 copy_and_next(dest_ptr
, normal
, 3 * sizeof(float));
4166 copy_and_next(dest_conv
, normal
, 3 * sizeof(float));
4170 if (DestFVF
& WINED3DFVF_DIFFUSE
) {
4171 const struct wined3d_stream_info_element
*element
= &stream_info
->elements
[WINED3D_FFP_DIFFUSE
];
4172 const DWORD
*color_d
= (const DWORD
*)(element
->data
+ i
* element
->stride
);
4173 if (!(stream_info
->use_map
& (1 << WINED3D_FFP_DIFFUSE
)))
4175 static BOOL warned
= FALSE
;
4178 ERR("No diffuse color in source, but destination has one\n");
4182 *( (DWORD
*) dest_ptr
) = 0xffffffff;
4183 dest_ptr
+= sizeof(DWORD
);
4186 *( (DWORD
*) dest_conv
) = 0xffffffff;
4187 dest_conv
+= sizeof(DWORD
);
4191 copy_and_next(dest_ptr
, color_d
, sizeof(DWORD
));
4193 *( (DWORD
*) dest_conv
) = (*color_d
& 0xff00ff00) ; /* Alpha + green */
4194 *( (DWORD
*) dest_conv
) |= (*color_d
& 0x00ff0000) >> 16; /* Red */
4195 *( (DWORD
*) dest_conv
) |= (*color_d
& 0xff0000ff) << 16; /* Blue */
4196 dest_conv
+= sizeof(DWORD
);
4201 if (DestFVF
& WINED3DFVF_SPECULAR
)
4203 /* What's the color value in the feedback buffer? */
4204 const struct wined3d_stream_info_element
*element
= &stream_info
->elements
[WINED3D_FFP_SPECULAR
];
4205 const DWORD
*color_s
= (const DWORD
*)(element
->data
+ i
* element
->stride
);
4206 if (!(stream_info
->use_map
& (1 << WINED3D_FFP_SPECULAR
)))
4208 static BOOL warned
= FALSE
;
4211 ERR("No specular color in source, but destination has one\n");
4215 *( (DWORD
*) dest_ptr
) = 0xFF000000;
4216 dest_ptr
+= sizeof(DWORD
);
4219 *( (DWORD
*) dest_conv
) = 0xFF000000;
4220 dest_conv
+= sizeof(DWORD
);
4224 copy_and_next(dest_ptr
, color_s
, sizeof(DWORD
));
4226 *( (DWORD
*) dest_conv
) = (*color_s
& 0xff00ff00) ; /* Alpha + green */
4227 *( (DWORD
*) dest_conv
) |= (*color_s
& 0x00ff0000) >> 16; /* Red */
4228 *( (DWORD
*) dest_conv
) |= (*color_s
& 0xff0000ff) << 16; /* Blue */
4229 dest_conv
+= sizeof(DWORD
);
4234 for (tex_index
= 0; tex_index
< numTextures
; tex_index
++) {
4235 const struct wined3d_stream_info_element
*element
= &stream_info
->elements
[WINED3D_FFP_TEXCOORD0
+ tex_index
];
4236 const float *tex_coord
= (const float *)(element
->data
+ i
* element
->stride
);
4237 if (!(stream_info
->use_map
& (1 << (WINED3D_FFP_TEXCOORD0
+ tex_index
))))
4239 ERR("No source texture, but destination requests one\n");
4240 dest_ptr
+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
4241 if(dest_conv
) dest_conv
+= GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
4244 copy_and_next(dest_ptr
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
4246 copy_and_next(dest_conv
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
4256 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, dest
->buffer_object
));
4257 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4258 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB
, dwDestIndex
* get_flexible_vertex_size(DestFVF
),
4259 dwCount
* get_flexible_vertex_size(DestFVF
),
4261 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4265 HeapFree(GetProcessHeap(), 0, dest_conv_addr
);
4270 #undef copy_and_next
4272 /* Do not call while under the GL lock. */
4273 static HRESULT WINAPI
IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice
*iface
, UINT SrcStartIndex
, UINT DestIndex
,
4274 UINT VertexCount
, IWineD3DBuffer
*pDestBuffer
, struct wined3d_vertex_declaration
*pVertexDecl
, DWORD flags
,
4277 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4278 struct wined3d_stream_info stream_info
;
4279 const struct wined3d_gl_info
*gl_info
;
4280 struct wined3d_context
*context
;
4281 BOOL vbo
= FALSE
, streamWasUP
= This
->stateBlock
->state
.user_stream
;
4284 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This
, SrcStartIndex
, DestIndex
, VertexCount
, pDestBuffer
, pVertexDecl
, flags
);
4287 ERR("Output vertex declaration not implemented yet\n");
4290 /* Need any context to write to the vbo. */
4291 context
= context_acquire(This
, NULL
);
4292 gl_info
= context
->gl_info
;
4294 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4295 * control the streamIsUP flag, thus restore it afterwards.
4297 This
->stateBlock
->state
.user_stream
= FALSE
;
4298 device_stream_info_from_declaration(This
, FALSE
, &stream_info
, &vbo
);
4299 This
->stateBlock
->state
.user_stream
= streamWasUP
;
4301 if(vbo
|| SrcStartIndex
) {
4303 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4304 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4306 * Also get the start index in, but only loop over all elements if there's something to add at all.
4308 for (i
= 0; i
< (sizeof(stream_info
.elements
) / sizeof(*stream_info
.elements
)); ++i
)
4310 struct wined3d_stream_info_element
*e
;
4312 if (!(stream_info
.use_map
& (1 << i
))) continue;
4314 e
= &stream_info
.elements
[i
];
4315 if (e
->buffer_object
)
4317 struct wined3d_buffer
*vb
= This
->stateBlock
->state
.streams
[e
->stream_idx
].buffer
;
4318 e
->buffer_object
= 0;
4319 e
->data
= (BYTE
*)((ULONG_PTR
)e
->data
+ (ULONG_PTR
)buffer_get_sysmem(vb
, gl_info
));
4321 GL_EXTCALL(glDeleteBuffersARB(1, &vb
->buffer_object
));
4322 vb
->buffer_object
= 0;
4325 if (e
->data
) e
->data
+= e
->stride
* SrcStartIndex
;
4329 hr
= process_vertices_strided(This
, DestIndex
, VertexCount
, &stream_info
,
4330 (struct wined3d_buffer
*)pDestBuffer
, flags
, DestFVF
);
4332 context_release(context
);
4338 * Get / Set Texture Stage States
4339 * TODO: Verify against dx9 definitions
4341 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD Value
)
4343 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4344 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
4347 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This
, Stage
, debug_d3dtexturestate(Type
), Type
, Value
);
4349 if (Type
> WINED3D_HIGHEST_TEXTURE_STATE
)
4351 WARN("Invalid Type %d passed.\n", Type
);
4355 if (Stage
>= gl_info
->limits
.texture_stages
)
4357 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
4358 Stage
, gl_info
->limits
.texture_stages
- 1);
4362 oldValue
= This
->updateStateBlock
->state
.texture_states
[Stage
][Type
];
4363 This
->updateStateBlock
->changed
.textureState
[Stage
] |= 1 << Type
;
4364 This
->updateStateBlock
->state
.texture_states
[Stage
][Type
] = Value
;
4366 if (This
->isRecordingState
) {
4367 TRACE("Recording... not performing anything\n");
4371 /* Checked after the assignments to allow proper stateblock recording */
4372 if(oldValue
== Value
) {
4373 TRACE("App is setting the old value over, nothing to do\n");
4377 if (Stage
> This
->stateBlock
->state
.lowest_disabled_stage
4378 && This
->StateTable
[STATE_TEXTURESTAGE(0, Type
)].representative
4379 == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP
))
4381 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4382 * Changes in other states are important on disabled stages too
4387 if(Type
== WINED3DTSS_COLOROP
) {
4390 if(Value
== WINED3DTOP_DISABLE
&& oldValue
!= WINED3DTOP_DISABLE
) {
4391 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4392 * they have to be disabled
4394 * The current stage is dirtified below.
4396 for (i
= Stage
+ 1; i
< This
->stateBlock
->state
.lowest_disabled_stage
; ++i
)
4398 TRACE("Additionally dirtifying stage %u\n", i
);
4399 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
4401 This
->stateBlock
->state
.lowest_disabled_stage
= Stage
;
4402 TRACE("New lowest disabled: %u\n", Stage
);
4403 } else if(Value
!= WINED3DTOP_DISABLE
&& oldValue
== WINED3DTOP_DISABLE
) {
4404 /* Previously disabled stage enabled. Stages above it may need enabling
4405 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4406 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4408 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4411 for (i
= Stage
+ 1; i
< This
->adapter
->gl_info
.limits
.texture_stages
; ++i
)
4413 if (This
->updateStateBlock
->state
.texture_states
[i
][WINED3DTSS_COLOROP
] == WINED3DTOP_DISABLE
)
4415 TRACE("Additionally dirtifying stage %u due to enable\n", i
);
4416 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
4418 This
->stateBlock
->state
.lowest_disabled_stage
= i
;
4419 TRACE("New lowest disabled: %u\n", i
);
4423 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, Type
));
4428 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD
*pValue
)
4430 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4432 TRACE("iface %p, stage %u, state %s, value %p.\n",
4433 iface
, Stage
, debug_d3dtexturestate(Type
), pValue
);
4435 if (Type
> WINED3D_HIGHEST_TEXTURE_STATE
)
4437 WARN("Invalid Type %d passed.\n", Type
);
4441 *pValue
= This
->updateStateBlock
->state
.texture_states
[Stage
][Type
];
4442 TRACE("Returning %#x.\n", *pValue
);
4450 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTexture(IWineD3DDevice
*iface
,
4451 DWORD stage
, IWineD3DBaseTexture
*texture
)
4453 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4454 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
4455 IWineD3DBaseTexture
*prev
;
4457 TRACE("iface %p, stage %u, texture %p.\n", iface
, stage
, texture
);
4459 if (stage
>= WINED3DVERTEXTEXTURESAMPLER0
&& stage
<= WINED3DVERTEXTEXTURESAMPLER3
)
4460 stage
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
4462 /* Windows accepts overflowing this array... we do not. */
4463 if (stage
>= sizeof(This
->stateBlock
->state
.textures
) / sizeof(*This
->stateBlock
->state
.textures
))
4465 WARN("Ignoring invalid stage %u.\n", stage
);
4469 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4470 if (texture
&& ((IWineD3DTextureImpl
*)texture
)->resource
.pool
== WINED3DPOOL_SCRATCH
)
4472 WARN("Rejecting attempt to set scratch texture.\n");
4473 return WINED3DERR_INVALIDCALL
;
4476 This
->updateStateBlock
->changed
.textures
|= 1 << stage
;
4478 prev
= (IWineD3DBaseTexture
*)This
->updateStateBlock
->state
.textures
[stage
];
4479 TRACE("Previous texture %p.\n", prev
);
4481 if (texture
== prev
)
4483 TRACE("App is setting the same texture again, nothing to do.\n");
4487 TRACE("Setting new texture to %p.\n", texture
);
4488 This
->updateStateBlock
->state
.textures
[stage
] = (IWineD3DBaseTextureImpl
*)texture
;
4490 if (This
->isRecordingState
)
4492 TRACE("Recording... not performing anything\n");
4494 if (texture
) IWineD3DBaseTexture_AddRef(texture
);
4495 if (prev
) IWineD3DBaseTexture_Release(prev
);
4502 IWineD3DBaseTextureImpl
*t
= (IWineD3DBaseTextureImpl
*)texture
;
4503 LONG bind_count
= InterlockedIncrement(&t
->baseTexture
.bindCount
);
4504 GLenum dimensions
= t
->baseTexture
.target
;
4506 IWineD3DBaseTexture_AddRef(texture
);
4508 if (!prev
|| dimensions
!= ((IWineD3DBaseTextureImpl
*)prev
)->baseTexture
.target
)
4509 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADER
);
4511 if (!prev
&& stage
< gl_info
->limits
.texture_stages
)
4513 /* The source arguments for color and alpha ops have different
4514 * meanings when a NULL texture is bound, so the COLOROP and
4515 * ALPHAOP have to be dirtified. */
4516 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, WINED3DTSS_COLOROP
));
4517 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, WINED3DTSS_ALPHAOP
));
4520 if (bind_count
== 1) t
->baseTexture
.sampler
= stage
;
4525 IWineD3DBaseTextureImpl
*t
= (IWineD3DBaseTextureImpl
*)prev
;
4526 LONG bind_count
= InterlockedDecrement(&t
->baseTexture
.bindCount
);
4528 IWineD3DBaseTexture_Release(prev
);
4530 if (!texture
&& stage
< gl_info
->limits
.texture_stages
)
4532 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, WINED3DTSS_COLOROP
));
4533 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, WINED3DTSS_ALPHAOP
));
4536 if (bind_count
&& t
->baseTexture
.sampler
== stage
)
4540 /* Search for other stages the texture is bound to. Shouldn't
4541 * happen if applications bind textures to a single stage only. */
4542 TRACE("Searching for other stages the texture is bound to.\n");
4543 for (i
= 0; i
< MAX_COMBINED_SAMPLERS
; ++i
)
4545 if (This
->updateStateBlock
->state
.textures
[i
] == t
)
4547 TRACE("Texture is also bound to stage %u.\n", i
);
4548 t
->baseTexture
.sampler
= i
;
4555 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(stage
));
4560 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTexture(IWineD3DDevice
*iface
, DWORD Stage
, IWineD3DBaseTexture
** ppTexture
) {
4561 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4563 TRACE("(%p) : Stage %#x, ppTexture %p\n", This
, Stage
, ppTexture
);
4565 if (Stage
>= WINED3DVERTEXTEXTURESAMPLER0
&& Stage
<= WINED3DVERTEXTEXTURESAMPLER3
) {
4566 Stage
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
4569 if (Stage
>= sizeof(This
->stateBlock
->state
.textures
) / sizeof(*This
->stateBlock
->state
.textures
))
4571 ERR("Current stage overflows textures array (stage %d)\n", Stage
);
4572 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
4575 *ppTexture
= (IWineD3DBaseTexture
*)This
->stateBlock
->state
.textures
[Stage
];
4577 IWineD3DBaseTexture_AddRef(*ppTexture
);
4579 TRACE("(%p) : Returning %p\n", This
, *ppTexture
);
4587 static HRESULT WINAPI
IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice
*iface
, UINT swapchain_idx
,
4588 UINT backbuffer_idx
, WINED3DBACKBUFFER_TYPE backbuffer_type
, IWineD3DSurface
**backbuffer
)
4590 IWineD3DSwapChain
*swapchain
;
4593 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4594 iface
, swapchain_idx
, backbuffer_idx
, backbuffer_type
, backbuffer
);
4596 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, swapchain_idx
, &swapchain
);
4599 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx
, hr
);
4603 hr
= IWineD3DSwapChain_GetBackBuffer(swapchain
, backbuffer_idx
, backbuffer_type
, backbuffer
);
4604 IWineD3DSwapChain_Release(swapchain
);
4607 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx
, hr
);
4614 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice
*iface
, WINED3DCAPS
*caps
)
4616 IWineD3DDeviceImpl
*device
= (IWineD3DDeviceImpl
*)iface
;
4618 TRACE("iface %p, caps %p.\n", iface
, caps
);
4620 return wined3d_get_device_caps(device
->wined3d
, device
->adapter
->ordinal
, device
->devType
, caps
);
4623 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DDISPLAYMODE
* pMode
) {
4624 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4625 IWineD3DSwapChain
*swapChain
;
4628 if(iSwapChain
> 0) {
4629 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
4630 if (hr
== WINED3D_OK
) {
4631 hr
= IWineD3DSwapChain_GetDisplayMode(swapChain
, pMode
);
4632 IWineD3DSwapChain_Release(swapChain
);
4634 FIXME("(%p) Error getting display mode\n", This
);
4637 /* Don't read the real display mode,
4638 but return the stored mode instead. X11 can't change the color
4639 depth, and some apps are pretty angry if they SetDisplayMode from
4640 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4642 Also don't relay to the swapchain because with ddraw it's possible
4643 that there isn't a swapchain at all */
4644 pMode
->Width
= This
->ddraw_width
;
4645 pMode
->Height
= This
->ddraw_height
;
4646 pMode
->Format
= This
->ddraw_format
;
4647 pMode
->RefreshRate
= 0;
4655 * Stateblock related functions
4658 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice
*iface
)
4660 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4661 struct wined3d_stateblock
*stateblock
;
4664 TRACE("(%p)\n", This
);
4666 if (This
->isRecordingState
) return WINED3DERR_INVALIDCALL
;
4668 hr
= IWineD3DDeviceImpl_CreateStateBlock(iface
, WINED3DSBT_RECORDED
, &stateblock
);
4669 if (FAILED(hr
)) return hr
;
4671 wined3d_stateblock_decref(This
->updateStateBlock
);
4672 This
->updateStateBlock
= stateblock
;
4673 This
->isRecordingState
= TRUE
;
4675 TRACE("(%p) recording stateblock %p\n", This
, stateblock
);
4680 static HRESULT WINAPI
IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice
*iface
,
4681 struct wined3d_stateblock
**stateblock
)
4683 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4684 struct wined3d_stateblock
*object
= This
->updateStateBlock
;
4686 TRACE("iface %p, stateblock %p.\n", iface
, stateblock
);
4688 if (!This
->isRecordingState
) {
4689 WARN("(%p) not recording! returning error\n", This
);
4691 return WINED3DERR_INVALIDCALL
;
4694 stateblock_init_contained_states(object
);
4696 *stateblock
= object
;
4697 This
->isRecordingState
= FALSE
;
4698 This
->updateStateBlock
= This
->stateBlock
;
4699 wined3d_stateblock_incref(This
->updateStateBlock
);
4701 TRACE("Returning stateblock %p.\n", *stateblock
);
4707 * Scene related functions
4709 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginScene(IWineD3DDevice
*iface
) {
4710 /* At the moment we have no need for any functionality at the beginning
4712 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4713 TRACE("(%p)\n", This
);
4716 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4717 return WINED3DERR_INVALIDCALL
;
4719 This
->inScene
= TRUE
;
4723 static HRESULT WINAPI
IWineD3DDeviceImpl_EndScene(IWineD3DDevice
*iface
)
4725 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4726 struct wined3d_context
*context
;
4728 TRACE("(%p)\n", This
);
4730 if(!This
->inScene
) {
4731 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4732 return WINED3DERR_INVALIDCALL
;
4735 context
= context_acquire(This
, NULL
);
4736 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4738 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4740 context_release(context
);
4742 This
->inScene
= FALSE
;
4746 static HRESULT WINAPI
IWineD3DDeviceImpl_Present(IWineD3DDevice
*iface
,
4747 const RECT
*pSourceRect
, const RECT
*pDestRect
,
4748 HWND hDestWindowOverride
, const RGNDATA
*pDirtyRegion
)
4750 IWineD3DSwapChain
*swapChain
= NULL
;
4752 int swapchains
= IWineD3DDeviceImpl_GetNumberOfSwapChains(iface
);
4754 TRACE("iface %p.\n", iface
);
4756 for(i
= 0 ; i
< swapchains
; i
++) {
4758 IWineD3DDeviceImpl_GetSwapChain(iface
, i
, &swapChain
);
4759 TRACE("Presenting chain %d, %p.\n", i
, swapChain
);
4760 IWineD3DSwapChain_Present(swapChain
, pSourceRect
, pDestRect
, hDestWindowOverride
, pDirtyRegion
, 0);
4761 IWineD3DSwapChain_Release(swapChain
);
4767 /* Do not call while under the GL lock. */
4768 static HRESULT WINAPI
IWineD3DDeviceImpl_Clear(IWineD3DDevice
*iface
, DWORD rect_count
,
4769 const RECT
*rects
, DWORD flags
, WINED3DCOLOR color
, float depth
, DWORD stencil
)
4771 const WINED3DCOLORVALUE c
= {D3DCOLOR_R(color
), D3DCOLOR_G(color
), D3DCOLOR_B(color
), D3DCOLOR_A(color
)};
4772 IWineD3DDeviceImpl
*device
= (IWineD3DDeviceImpl
*)iface
;
4775 TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, depth %.8e, stencil %u.\n",
4776 iface
, rect_count
, rects
, flags
, color
, depth
, stencil
);
4778 if (flags
& (WINED3DCLEAR_ZBUFFER
| WINED3DCLEAR_STENCIL
) && !device
->depth_stencil
)
4780 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4781 /* TODO: What about depth stencil buffers without stencil bits? */
4782 return WINED3DERR_INVALIDCALL
;
4785 device_get_draw_rect(device
, &draw_rect
);
4787 return device_clear_render_targets(device
, device
->adapter
->gl_info
.limits
.buffers
,
4788 device
->render_targets
, rect_count
, rects
, &draw_rect
, flags
, &c
, depth
, stencil
);
4795 static void WINAPI
IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice
*iface
,
4796 WINED3DPRIMITIVETYPE primitive_type
)
4798 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4800 TRACE("iface %p, primitive_type %s\n", iface
, debug_d3dprimitivetype(primitive_type
));
4802 This
->updateStateBlock
->changed
.primitive_type
= TRUE
;
4803 This
->updateStateBlock
->state
.gl_primitive_type
= gl_primitive_type_from_d3d(primitive_type
);
4806 static void WINAPI
IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice
*iface
,
4807 WINED3DPRIMITIVETYPE
*primitive_type
)
4809 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4811 TRACE("iface %p, primitive_type %p\n", iface
, primitive_type
);
4813 *primitive_type
= d3d_primitive_type_from_gl(This
->stateBlock
->state
.gl_primitive_type
);
4815 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type
));
4818 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice
*iface
, UINT StartVertex
, UINT vertex_count
)
4820 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4822 TRACE("(%p) : start %u, count %u\n", This
, StartVertex
, vertex_count
);
4824 if (!This
->stateBlock
->state
.vertex_declaration
)
4826 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
4827 return WINED3DERR_INVALIDCALL
;
4830 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4831 if (This
->stateBlock
->state
.user_stream
)
4833 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
4834 This
->stateBlock
->state
.user_stream
= FALSE
;
4837 if (This
->stateBlock
->state
.load_base_vertex_index
)
4839 This
->stateBlock
->state
.load_base_vertex_index
= 0;
4840 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
4842 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4843 drawPrimitive(This
, vertex_count
, StartVertex
/* start_idx */, 0 /* indxSize */, NULL
/* indxData */);
4847 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice
*iface
, UINT startIndex
, UINT index_count
)
4849 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4850 struct wined3d_buffer
*index_buffer
;
4854 index_buffer
= This
->stateBlock
->state
.index_buffer
;
4857 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4858 * without an index buffer set. (The first time at least...)
4859 * D3D8 simply dies, but I doubt it can do much harm to return
4860 * D3DERR_INVALIDCALL there as well. */
4861 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This
);
4862 return WINED3DERR_INVALIDCALL
;
4865 if (!This
->stateBlock
->state
.vertex_declaration
)
4867 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
4868 return WINED3DERR_INVALIDCALL
;
4871 if (This
->stateBlock
->state
.user_stream
)
4873 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
4874 This
->stateBlock
->state
.user_stream
= FALSE
;
4876 vbo
= index_buffer
->buffer_object
;
4878 TRACE("(%p) : startIndex %u, index count %u.\n", This
, startIndex
, index_count
);
4880 if (This
->stateBlock
->state
.index_format
== WINED3DFMT_R16_UINT
)
4885 if (This
->stateBlock
->state
.load_base_vertex_index
!= This
->stateBlock
->state
.base_vertex_index
)
4887 This
->stateBlock
->state
.load_base_vertex_index
= This
->stateBlock
->state
.base_vertex_index
;
4888 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
4891 drawPrimitive(This
, index_count
, startIndex
, idxStride
,
4892 vbo
? NULL
: index_buffer
->resource
.allocatedMemory
);
4897 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice
*iface
, UINT vertex_count
,
4898 const void *pVertexStreamZeroData
, UINT VertexStreamZeroStride
)
4900 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4901 struct wined3d_stream_state
*stream
;
4904 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4905 This
, vertex_count
, pVertexStreamZeroData
, VertexStreamZeroStride
);
4907 if (!This
->stateBlock
->state
.vertex_declaration
)
4909 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
4910 return WINED3DERR_INVALIDCALL
;
4913 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4914 stream
= &This
->stateBlock
->state
.streams
[0];
4915 vb
= (IWineD3DBuffer
*)stream
->buffer
;
4916 stream
->buffer
= (struct wined3d_buffer
*)pVertexStreamZeroData
;
4917 if (vb
) IWineD3DBuffer_Release(vb
);
4919 stream
->stride
= VertexStreamZeroStride
;
4920 This
->stateBlock
->state
.user_stream
= TRUE
;
4921 This
->stateBlock
->state
.load_base_vertex_index
= 0;
4923 /* TODO: Only mark dirty if drawing from a different UP address */
4924 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
4926 drawPrimitive(This
, vertex_count
, 0 /* start_idx */, 0 /* indxSize*/, NULL
/* indxData */);
4928 /* MSDN specifies stream zero settings must be set to NULL */
4929 stream
->buffer
= NULL
;
4932 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4933 * the new stream sources or use UP drawing again
4938 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice
*iface
,
4939 UINT index_count
, const void *pIndexData
, enum wined3d_format_id IndexDataFormat
,
4940 const void *pVertexStreamZeroData
, UINT VertexStreamZeroStride
)
4943 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4944 struct wined3d_stream_state
*stream
;
4948 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4949 This
, index_count
, pIndexData
, IndexDataFormat
, pVertexStreamZeroData
, VertexStreamZeroStride
);
4951 if (!This
->stateBlock
->state
.vertex_declaration
)
4953 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
4954 return WINED3DERR_INVALIDCALL
;
4957 if (IndexDataFormat
== WINED3DFMT_R16_UINT
) {
4963 stream
= &This
->stateBlock
->state
.streams
[0];
4964 vb
= (IWineD3DBuffer
*)stream
->buffer
;
4965 stream
->buffer
= (struct wined3d_buffer
*)pVertexStreamZeroData
;
4966 if (vb
) IWineD3DBuffer_Release(vb
);
4968 stream
->stride
= VertexStreamZeroStride
;
4969 This
->stateBlock
->state
.user_stream
= TRUE
;
4971 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4972 This
->stateBlock
->state
.base_vertex_index
= 0;
4973 This
->stateBlock
->state
.load_base_vertex_index
= 0;
4974 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4975 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
4976 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
4978 drawPrimitive(This
, index_count
, 0 /* start_idx */, idxStride
, pIndexData
);
4980 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4981 stream
->buffer
= NULL
;
4983 ib
= (IWineD3DBuffer
*)This
->stateBlock
->state
.index_buffer
;
4986 IWineD3DBuffer_Release(ib
);
4987 This
->stateBlock
->state
.index_buffer
= NULL
;
4989 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4990 * SetStreamSource to specify a vertex buffer
4996 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice
*iface
,
4997 UINT vertex_count
, const WineDirect3DVertexStridedData
*DrawPrimStrideData
)
4999 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5001 /* Mark the state dirty until we have nicer tracking
5002 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5005 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
5006 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5007 This
->stateBlock
->state
.base_vertex_index
= 0;
5008 This
->up_strided
= DrawPrimStrideData
;
5009 drawPrimitive(This
, vertex_count
, 0, 0, NULL
);
5010 This
->up_strided
= NULL
;
5014 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice
*iface
,
5015 UINT vertex_count
, const WineDirect3DVertexStridedData
*DrawPrimStrideData
,
5016 UINT NumVertices
, const void *pIndexData
, enum wined3d_format_id IndexDataFormat
)
5018 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5019 DWORD idxSize
= (IndexDataFormat
== WINED3DFMT_R32_UINT
? 4 : 2);
5021 /* Mark the state dirty until we have nicer tracking
5022 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5025 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
5026 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5027 This
->stateBlock
->state
.user_stream
= TRUE
;
5028 This
->stateBlock
->state
.base_vertex_index
= 0;
5029 This
->up_strided
= DrawPrimStrideData
;
5030 drawPrimitive(This
, vertex_count
, 0 /* start_idx */, idxSize
, pIndexData
);
5031 This
->up_strided
= NULL
;
5035 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
5036 static HRESULT
IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice
*iface
,
5037 IWineD3DVolume
*pSourceVolume
, IWineD3DVolume
*pDestinationVolume
)
5039 WINED3DLOCKED_BOX src
;
5040 WINED3DLOCKED_BOX dst
;
5043 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
5044 iface
, pSourceVolume
, pDestinationVolume
);
5046 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5047 * dirtification to improve loading performance.
5049 hr
= IWineD3DVolume_Map(pSourceVolume
, &src
, NULL
, WINED3DLOCK_READONLY
);
5050 if (FAILED(hr
)) return hr
;
5051 hr
= IWineD3DVolume_Map(pDestinationVolume
, &dst
, NULL
, WINED3DLOCK_DISCARD
);
5054 IWineD3DVolume_Unmap(pSourceVolume
);
5058 memcpy(dst
.pBits
, src
.pBits
, ((IWineD3DVolumeImpl
*) pDestinationVolume
)->resource
.size
);
5060 hr
= IWineD3DVolume_Unmap(pDestinationVolume
);
5062 IWineD3DVolume_Unmap(pSourceVolume
);
5064 hr
= IWineD3DVolume_Unmap(pSourceVolume
);
5069 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice
*iface
,
5070 IWineD3DBaseTexture
*src_texture
, IWineD3DBaseTexture
*dst_texture
)
5072 unsigned int level_count
, i
;
5073 WINED3DRESOURCETYPE type
;
5076 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface
, src_texture
, dst_texture
);
5078 /* Verify that the source and destination textures are non-NULL. */
5079 if (!src_texture
|| !dst_texture
)
5081 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
5082 return WINED3DERR_INVALIDCALL
;
5085 if (src_texture
== dst_texture
)
5087 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
5088 return WINED3DERR_INVALIDCALL
;
5091 /* Verify that the source and destination textures are the same type. */
5092 type
= IWineD3DBaseTexture_GetType(src_texture
);
5093 if (IWineD3DBaseTexture_GetType(dst_texture
) != type
)
5095 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
5096 return WINED3DERR_INVALIDCALL
;
5099 /* Check that both textures have the identical numbers of levels. */
5100 level_count
= IWineD3DBaseTexture_GetLevelCount(src_texture
);
5101 if (IWineD3DBaseTexture_GetLevelCount(dst_texture
) != level_count
)
5103 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
5104 return WINED3DERR_INVALIDCALL
;
5107 /* Make sure that the destination texture is loaded. */
5108 ((IWineD3DBaseTextureImpl
*)dst_texture
)->baseTexture
.texture_ops
->texture_preload(
5109 (IWineD3DBaseTextureImpl
*)dst_texture
, SRGB_RGB
);
5111 /* Update every surface level of the texture. */
5114 case WINED3DRTYPE_TEXTURE
:
5116 IWineD3DSurface
*src_surface
;
5117 IWineD3DSurface
*dst_surface
;
5119 for (i
= 0; i
< level_count
; ++i
)
5121 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)src_texture
, i
, &src_surface
);
5122 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)dst_texture
, i
, &dst_surface
);
5123 hr
= IWineD3DDevice_UpdateSurface(iface
, src_surface
, NULL
, dst_surface
, NULL
);
5124 IWineD3DSurface_Release(dst_surface
);
5125 IWineD3DSurface_Release(src_surface
);
5128 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr
);
5135 case WINED3DRTYPE_CUBETEXTURE
:
5137 IWineD3DSurface
*src_surface
;
5138 IWineD3DSurface
*dst_surface
;
5140 for (i
= 0; i
< level_count
* 6; ++i
)
5142 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)src_texture
, i
, &src_surface
);
5143 if (FAILED(hr
)) ERR("Failed to get src cube sub-resource %u, hr %#x.\n", i
, hr
);
5144 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)dst_texture
, i
, &dst_surface
);
5145 if (FAILED(hr
)) ERR("Failed to get dst cube sub-resource %u, hr %#x.\n", i
, hr
);
5146 hr
= IWineD3DDevice_UpdateSurface(iface
, src_surface
, NULL
, dst_surface
, NULL
);
5147 IWineD3DSurface_Release(dst_surface
);
5148 IWineD3DSurface_Release(src_surface
);
5151 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr
);
5158 case WINED3DRTYPE_VOLUMETEXTURE
:
5160 IWineD3DVolume
*src_volume
;
5161 IWineD3DVolume
*dst_volume
;
5163 for (i
= 0; i
< level_count
; ++i
)
5165 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture
*)src_texture
, i
, &src_volume
);
5166 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture
*)dst_texture
, i
, &dst_volume
);
5167 hr
= IWineD3DDeviceImpl_UpdateVolume(iface
, src_volume
, dst_volume
);
5168 IWineD3DVolume_Release(dst_volume
);
5169 IWineD3DVolume_Release(src_volume
);
5172 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr
);
5180 FIXME("Unsupported texture type %#x.\n", type
);
5181 return WINED3DERR_INVALIDCALL
;
5187 static HRESULT WINAPI
IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice
*iface
,
5188 UINT swapchain_idx
, IWineD3DSurface
*dst_surface
)
5190 IWineD3DSwapChain
*swapchain
;
5193 TRACE("iface %p, swapchain_idx %u, dst_surface %p.\n", iface
, swapchain_idx
, dst_surface
);
5195 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, swapchain_idx
, &swapchain
);
5196 if (FAILED(hr
)) return hr
;
5198 hr
= IWineD3DSwapChain_GetFrontBufferData(swapchain
, dst_surface
);
5199 IWineD3DSwapChain_Release(swapchain
);
5204 static HRESULT WINAPI
IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice
*iface
, DWORD
* pNumPasses
) {
5205 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5206 IWineD3DBaseTextureImpl
*texture
;
5209 TRACE("(%p) : %p\n", This
, pNumPasses
);
5211 for (i
= 0; i
< MAX_COMBINED_SAMPLERS
; ++i
)
5213 if (This
->stateBlock
->state
.sampler_states
[i
][WINED3DSAMP_MINFILTER
] == WINED3DTEXF_NONE
)
5215 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i
);
5216 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER
;
5218 if (This
->stateBlock
->state
.sampler_states
[i
][WINED3DSAMP_MAGFILTER
] == WINED3DTEXF_NONE
)
5220 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i
);
5221 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER
;
5224 texture
= This
->stateBlock
->state
.textures
[i
];
5225 if (!texture
|| texture
->resource
.format
->flags
& WINED3DFMT_FLAG_FILTERING
) continue;
5227 if (This
->stateBlock
->state
.sampler_states
[i
][WINED3DSAMP_MAGFILTER
] != WINED3DTEXF_POINT
)
5229 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i
);
5232 if (This
->stateBlock
->state
.sampler_states
[i
][WINED3DSAMP_MINFILTER
] != WINED3DTEXF_POINT
)
5234 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i
);
5237 if (This
->stateBlock
->state
.sampler_states
[i
][WINED3DSAMP_MIPFILTER
] != WINED3DTEXF_NONE
5238 && This
->stateBlock
->state
.sampler_states
[i
][WINED3DSAMP_MIPFILTER
] != WINED3DTEXF_POINT
)
5240 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i
);
5245 /* return a sensible default */
5248 TRACE("returning D3D_OK\n");
5252 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl
*device
)
5256 for (i
= 0; i
< MAX_COMBINED_SAMPLERS
; ++i
)
5258 IWineD3DBaseTextureImpl
*texture
= device
->stateBlock
->state
.textures
[i
];
5259 if (texture
&& (texture
->resource
.format
->id
== WINED3DFMT_P8_UINT
5260 || texture
->resource
.format
->id
== WINED3DFMT_P8_UINT_A8_UNORM
))
5262 IWineD3DDeviceImpl_MarkStateDirty(device
, STATE_SAMPLER(i
));
5267 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, CONST PALETTEENTRY
* pEntries
) {
5268 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5271 PALETTEENTRY
**palettes
;
5273 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5275 if (PaletteNumber
>= MAX_PALETTES
) {
5276 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This
, PaletteNumber
, MAX_PALETTES
);
5277 return WINED3DERR_INVALIDCALL
;
5280 if (PaletteNumber
>= This
->NumberOfPalettes
) {
5281 NewSize
= This
->NumberOfPalettes
;
5284 } while(PaletteNumber
>= NewSize
);
5285 palettes
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, This
->palettes
, sizeof(PALETTEENTRY
*) * NewSize
);
5287 ERR("Out of memory!\n");
5288 return E_OUTOFMEMORY
;
5290 This
->palettes
= palettes
;
5291 This
->NumberOfPalettes
= NewSize
;
5294 if (!This
->palettes
[PaletteNumber
]) {
5295 This
->palettes
[PaletteNumber
] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY
) * 256);
5296 if (!This
->palettes
[PaletteNumber
]) {
5297 ERR("Out of memory!\n");
5298 return E_OUTOFMEMORY
;
5302 for (j
= 0; j
< 256; ++j
) {
5303 This
->palettes
[PaletteNumber
][j
].peRed
= pEntries
[j
].peRed
;
5304 This
->palettes
[PaletteNumber
][j
].peGreen
= pEntries
[j
].peGreen
;
5305 This
->palettes
[PaletteNumber
][j
].peBlue
= pEntries
[j
].peBlue
;
5306 This
->palettes
[PaletteNumber
][j
].peFlags
= pEntries
[j
].peFlags
;
5308 if (PaletteNumber
== This
->currentPalette
) dirtify_p8_texture_samplers(This
);
5309 TRACE("(%p) : returning\n", This
);
5313 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, PALETTEENTRY
* pEntries
) {
5314 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5316 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5317 if (PaletteNumber
>= This
->NumberOfPalettes
|| !This
->palettes
[PaletteNumber
]) {
5318 /* What happens in such situation isn't documented; Native seems to silently abort
5319 on such conditions. Return Invalid Call. */
5320 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This
, PaletteNumber
, This
->NumberOfPalettes
);
5321 return WINED3DERR_INVALIDCALL
;
5323 for (j
= 0; j
< 256; ++j
) {
5324 pEntries
[j
].peRed
= This
->palettes
[PaletteNumber
][j
].peRed
;
5325 pEntries
[j
].peGreen
= This
->palettes
[PaletteNumber
][j
].peGreen
;
5326 pEntries
[j
].peBlue
= This
->palettes
[PaletteNumber
][j
].peBlue
;
5327 pEntries
[j
].peFlags
= This
->palettes
[PaletteNumber
][j
].peFlags
;
5329 TRACE("(%p) : returning\n", This
);
5333 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT PaletteNumber
) {
5334 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5335 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
5336 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5337 (tested with reference rasterizer). Return Invalid Call. */
5338 if (PaletteNumber
>= This
->NumberOfPalettes
|| !This
->palettes
[PaletteNumber
]) {
5339 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This
, PaletteNumber
, This
->NumberOfPalettes
);
5340 return WINED3DERR_INVALIDCALL
;
5342 /*TODO: stateblocks */
5343 if (This
->currentPalette
!= PaletteNumber
) {
5344 This
->currentPalette
= PaletteNumber
;
5345 dirtify_p8_texture_samplers(This
);
5347 TRACE("(%p) : returning\n", This
);
5351 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT
* PaletteNumber
) {
5352 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5356 WARN("(%p) : returning Invalid Call\n", This
);
5357 return WINED3DERR_INVALIDCALL
;
5359 /*TODO: stateblocks */
5360 *PaletteNumber
= This
->currentPalette
;
5361 TRACE("(%p) : returning %u\n", This
, *PaletteNumber
);
5365 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice
*iface
, BOOL bSoftware
) {
5366 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5370 FIXME("(%p) : stub\n", This
);
5374 This
->softwareVertexProcessing
= bSoftware
;
5379 static BOOL WINAPI
IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice
*iface
) {
5380 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5384 FIXME("(%p) : stub\n", This
);
5387 return This
->softwareVertexProcessing
;
5390 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice
*iface
,
5391 UINT swapchain_idx
, WINED3DRASTER_STATUS
*raster_status
)
5393 IWineD3DSwapChain
*swapchain
;
5396 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5397 iface
, swapchain_idx
, raster_status
);
5399 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, swapchain_idx
, &swapchain
);
5402 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx
, hr
);
5406 hr
= IWineD3DSwapChain_GetRasterStatus(swapchain
, raster_status
);
5407 IWineD3DSwapChain_Release(swapchain
);
5410 WARN("Failed to get raster status, hr %#x.\n", hr
);
5417 static HRESULT WINAPI
IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice
*iface
, float nSegments
)
5420 if(nSegments
!= 0.0f
) {
5423 FIXME("iface %p, nSegments %.8e stub!\n", iface
, nSegments
);
5430 static float WINAPI
IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice
*iface
)
5435 FIXME("iface %p stub!\n", iface
);
5441 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice
*iface
,
5442 IWineD3DSurface
*src_surface
, const RECT
*src_rect
,
5443 IWineD3DSurface
*dst_surface
, const POINT
*dst_point
)
5445 IWineD3DSurfaceImpl
*src_impl
= (IWineD3DSurfaceImpl
*)src_surface
;
5446 IWineD3DSurfaceImpl
*dst_impl
= (IWineD3DSurfaceImpl
*)dst_surface
;
5447 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5448 const struct wined3d_format
*src_format
;
5449 const struct wined3d_format
*dst_format
;
5450 const struct wined3d_gl_info
*gl_info
;
5451 struct wined3d_context
*context
;
5452 const unsigned char *data
;
5453 UINT update_w
, update_h
;
5454 CONVERT_TYPES convert
;
5458 struct wined3d_format format
;
5460 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5461 iface
, src_surface
, wine_dbgstr_rect(src_rect
),
5462 dst_surface
, wine_dbgstr_point(dst_point
));
5464 if (src_impl
->resource
.pool
!= WINED3DPOOL_SYSTEMMEM
|| dst_impl
->resource
.pool
!= WINED3DPOOL_DEFAULT
)
5466 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5467 src_surface
, dst_surface
);
5468 return WINED3DERR_INVALIDCALL
;
5471 src_format
= src_impl
->resource
.format
;
5472 dst_format
= dst_impl
->resource
.format
;
5474 if (src_format
->id
!= dst_format
->id
)
5476 WARN("Source and destination surfaces should have the same format.\n");
5477 return WINED3DERR_INVALIDCALL
;
5480 dst_x
= dst_point
? dst_point
->x
: 0;
5481 dst_y
= dst_point
? dst_point
->y
: 0;
5483 /* This call loads the OpenGL surface directly, instead of copying the
5484 * surface to the destination's sysmem copy. If surface conversion is
5485 * needed, use BltFast instead to copy in sysmem and use regular surface
5487 d3dfmt_get_conv(dst_impl
, FALSE
, TRUE
, &format
, &convert
);
5488 if (convert
!= NO_CONVERSION
|| format
.convert
)
5489 return IWineD3DSurface_BltFast(dst_surface
, dst_x
, dst_y
, src_surface
, src_rect
, 0);
5491 context
= context_acquire(This
, NULL
);
5492 gl_info
= context
->gl_info
;
5495 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
5496 checkGLcall("glActiveTextureARB");
5499 /* Make sure the surface is loaded and up to date */
5500 surface_internal_preload(dst_impl
, SRGB_RGB
);
5501 surface_bind(dst_impl
, FALSE
);
5503 src_w
= src_impl
->currentDesc
.Width
;
5504 src_h
= src_impl
->currentDesc
.Height
;
5505 update_w
= src_rect
? src_rect
->right
- src_rect
->left
: src_w
;
5506 update_h
= src_rect
? src_rect
->bottom
- src_rect
->top
: src_h
;
5508 data
= src_impl
->resource
.allocatedMemory
;
5509 if (!data
) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5513 if (dst_format
->flags
& WINED3DFMT_FLAG_COMPRESSED
)
5515 UINT row_length
= wined3d_format_calculate_size(src_format
, 1, update_w
, 1);
5516 UINT row_count
= (update_h
+ src_format
->block_height
- 1) / src_format
->block_height
;
5517 UINT src_pitch
= wined3d_format_calculate_size(src_format
, 1, src_w
, 1);
5521 data
+= (src_rect
->top
/ src_format
->block_height
) * src_pitch
;
5522 data
+= (src_rect
->left
/ src_format
->block_width
) * src_format
->block_byte_count
;
5525 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5526 "format %#x, image_size %#x, data %p.\n", dst_impl
->texture_target
, dst_impl
->texture_level
,
5527 dst_x
, dst_y
, update_w
, update_h
, dst_format
->glFormat
, row_count
* row_length
, data
);
5529 if (row_length
== src_pitch
)
5531 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl
->texture_target
, dst_impl
->texture_level
,
5532 dst_x
, dst_y
, update_w
, update_h
, dst_format
->glInternal
, row_count
* row_length
, data
));
5538 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5539 * can't use the unpack row length like below. */
5540 for (row
= 0, y
= dst_y
; row
< row_count
; ++row
)
5542 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl
->texture_target
, dst_impl
->texture_level
,
5543 dst_x
, y
, update_w
, src_format
->block_height
, dst_format
->glInternal
, row_length
, data
));
5544 y
+= src_format
->block_height
;
5548 checkGLcall("glCompressedTexSubImage2DARB");
5554 data
+= src_rect
->top
* src_w
* src_format
->byte_count
;
5555 data
+= src_rect
->left
* src_format
->byte_count
;
5558 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5559 dst_impl
->texture_target
, dst_impl
->texture_level
, dst_x
, dst_y
,
5560 update_w
, update_h
, dst_format
->glFormat
, dst_format
->glType
, data
);
5562 glPixelStorei(GL_UNPACK_ROW_LENGTH
, src_w
);
5563 glTexSubImage2D(dst_impl
->texture_target
, dst_impl
->texture_level
, dst_x
, dst_y
,
5564 update_w
, update_h
, dst_format
->glFormat
, dst_format
->glType
, data
);
5565 glPixelStorei(GL_UNPACK_ROW_LENGTH
, 0);
5566 checkGLcall("glTexSubImage2D");
5570 context_release(context
);
5572 surface_modify_location(dst_impl
, SFLAG_INTEXTURE
, TRUE
);
5573 sampler
= This
->rev_tex_unit_map
[0];
5574 if (sampler
!= WINED3D_UNMAPPED_STAGE
)
5576 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(sampler
));
5582 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice
*iface
, UINT Handle
, CONST
float* pNumSegs
, CONST WINED3DRECTPATCH_INFO
* pRectPatchInfo
) {
5583 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5584 struct WineD3DRectPatch
*patch
;
5585 GLenum old_primitive_type
;
5589 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This
, Handle
, pNumSegs
, pRectPatchInfo
);
5591 if(!(Handle
|| pRectPatchInfo
)) {
5592 /* TODO: Write a test for the return value, thus the FIXME */
5593 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5594 return WINED3DERR_INVALIDCALL
;
5598 i
= PATCHMAP_HASHFUNC(Handle
);
5600 LIST_FOR_EACH(e
, &This
->patches
[i
]) {
5601 patch
= LIST_ENTRY(e
, struct WineD3DRectPatch
, entry
);
5602 if(patch
->Handle
== Handle
) {
5609 TRACE("Patch does not exist. Creating a new one\n");
5610 patch
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*patch
));
5611 patch
->Handle
= Handle
;
5612 list_add_head(&This
->patches
[i
], &patch
->entry
);
5614 TRACE("Found existing patch %p\n", patch
);
5617 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5618 * attributes we have to tesselate, read back, and draw. This needs a patch
5619 * management structure instance. Create one.
5621 * A possible improvement is to check if a vertex shader is used, and if not directly
5624 FIXME("Drawing an uncached patch. This is slow\n");
5625 patch
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*patch
));
5628 if (pNumSegs
[0] != patch
->numSegs
[0] || pNumSegs
[1] != patch
->numSegs
[1]
5629 || pNumSegs
[2] != patch
->numSegs
[2] || pNumSegs
[3] != patch
->numSegs
[3]
5630 || (pRectPatchInfo
&& memcmp(pRectPatchInfo
, &patch
->RectPatchInfo
, sizeof(*pRectPatchInfo
))))
5633 TRACE("Tesselation density or patch info changed, retesselating\n");
5635 if(pRectPatchInfo
) {
5636 patch
->RectPatchInfo
= *pRectPatchInfo
;
5638 patch
->numSegs
[0] = pNumSegs
[0];
5639 patch
->numSegs
[1] = pNumSegs
[1];
5640 patch
->numSegs
[2] = pNumSegs
[2];
5641 patch
->numSegs
[3] = pNumSegs
[3];
5643 hr
= tesselate_rectpatch(This
, patch
);
5645 WARN("Patch tesselation failed\n");
5647 /* Do not release the handle to store the params of the patch */
5649 HeapFree(GetProcessHeap(), 0, patch
);
5655 This
->currentPatch
= patch
;
5656 old_primitive_type
= This
->stateBlock
->state
.gl_primitive_type
;
5657 This
->stateBlock
->state
.gl_primitive_type
= GL_TRIANGLES
;
5658 IWineD3DDevice_DrawPrimitiveStrided(iface
, patch
->numSegs
[0] * patch
->numSegs
[1] * 2 * 3, &patch
->strided
);
5659 This
->stateBlock
->state
.gl_primitive_type
= old_primitive_type
;
5660 This
->currentPatch
= NULL
;
5662 /* Destroy uncached patches */
5664 HeapFree(GetProcessHeap(), 0, patch
->mem
);
5665 HeapFree(GetProcessHeap(), 0, patch
);
5670 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice
*iface
,
5671 UINT handle
, const float *segment_count
, const WINED3DTRIPATCH_INFO
*patch_info
)
5673 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5674 iface
, handle
, segment_count
, patch_info
);
5679 static HRESULT WINAPI
IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice
*iface
, UINT Handle
) {
5680 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5682 struct WineD3DRectPatch
*patch
;
5684 TRACE("(%p) Handle(%d)\n", This
, Handle
);
5686 i
= PATCHMAP_HASHFUNC(Handle
);
5687 LIST_FOR_EACH(e
, &This
->patches
[i
]) {
5688 patch
= LIST_ENTRY(e
, struct WineD3DRectPatch
, entry
);
5689 if(patch
->Handle
== Handle
) {
5690 TRACE("Deleting patch %p\n", patch
);
5691 list_remove(&patch
->entry
);
5692 HeapFree(GetProcessHeap(), 0, patch
->mem
);
5693 HeapFree(GetProcessHeap(), 0, patch
);
5698 /* TODO: Write a test for the return value */
5699 FIXME("Attempt to destroy nonexistent patch\n");
5700 return WINED3DERR_INVALIDCALL
;
5703 /* Do not call while under the GL lock. */
5704 static HRESULT WINAPI
IWineD3DDeviceImpl_ColorFill(IWineD3DDevice
*iface
,
5705 IWineD3DSurface
*surface
, const RECT
*rect
, const WINED3DCOLORVALUE
*color
)
5707 IWineD3DSurfaceImpl
*s
= (IWineD3DSurfaceImpl
*)surface
;
5709 TRACE("iface %p, surface %p, rect %s, color {%.8e, %.8e, %.8e, %.8e}.\n",
5710 iface
, surface
, wine_dbgstr_rect(rect
),
5711 color
->r
, color
->g
, color
->b
, color
->a
);
5713 if (s
->resource
.pool
!= WINED3DPOOL_DEFAULT
&& s
->resource
.pool
!= WINED3DPOOL_SYSTEMMEM
)
5715 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5716 return WINED3DERR_INVALIDCALL
;
5719 return surface_color_fill(s
, rect
, color
);
5722 /* Do not call while under the GL lock. */
5723 static void WINAPI
IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice
*iface
,
5724 IWineD3DRendertargetView
*rendertarget_view
, const WINED3DCOLORVALUE
*color
)
5726 IWineD3DResource
*resource
;
5729 hr
= IWineD3DRendertargetView_GetResource(rendertarget_view
, &resource
);
5732 ERR("Failed to get resource, hr %#x\n", hr
);
5736 if (IWineD3DResource_GetType(resource
) != WINED3DRTYPE_SURFACE
)
5738 FIXME("Only supported on surface resources\n");
5739 IWineD3DResource_Release(resource
);
5743 hr
= surface_color_fill((IWineD3DSurfaceImpl
*)resource
, NULL
, color
);
5744 if (FAILED(hr
)) ERR("Color fill failed, hr %#x.\n", hr
);
5746 IWineD3DResource_Release(resource
);
5749 /* rendertarget and depth stencil functions */
5750 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice
*iface
,
5751 DWORD render_target_idx
, IWineD3DSurface
**render_target
)
5753 IWineD3DDeviceImpl
*device
= (IWineD3DDeviceImpl
*)iface
;
5755 TRACE("iface %p, render_target_idx %u, render_target %p.\n",
5756 iface
, render_target_idx
, render_target
);
5758 if (render_target_idx
>= device
->adapter
->gl_info
.limits
.buffers
)
5760 WARN("Only %u render targets are supported.\n", device
->adapter
->gl_info
.limits
.buffers
);
5761 return WINED3DERR_INVALIDCALL
;
5764 *render_target
= (IWineD3DSurface
*)device
->render_targets
[render_target_idx
];
5765 if (*render_target
) IWineD3DSurface_AddRef(*render_target
);
5767 TRACE("Returning render target %p.\n", *render_target
);
5772 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice
*iface
, IWineD3DSurface
**depth_stencil
)
5774 IWineD3DDeviceImpl
*device
= (IWineD3DDeviceImpl
*)iface
;
5776 TRACE("iface %p, depth_stencil %p.\n", iface
, depth_stencil
);
5778 *depth_stencil
= (IWineD3DSurface
*)device
->depth_stencil
;
5779 TRACE("Returning depth/stencil surface %p.\n", *depth_stencil
);
5780 if (!*depth_stencil
) return WINED3DERR_NOTFOUND
;
5781 IWineD3DSurface_AddRef(*depth_stencil
);
5786 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice
*iface
,
5787 DWORD render_target_idx
, IWineD3DSurface
*render_target
, BOOL set_viewport
)
5789 IWineD3DDeviceImpl
*device
= (IWineD3DDeviceImpl
*)iface
;
5790 IWineD3DSurfaceImpl
*prev
;
5792 TRACE("iface %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
5793 iface
, render_target_idx
, render_target
, set_viewport
);
5795 if (render_target_idx
>= device
->adapter
->gl_info
.limits
.buffers
)
5797 WARN("Only %u render targets are supported.\n", device
->adapter
->gl_info
.limits
.buffers
);
5798 return WINED3DERR_INVALIDCALL
;
5801 prev
= device
->render_targets
[render_target_idx
];
5802 if (render_target
== (IWineD3DSurface
*)prev
)
5804 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5808 /* Render target 0 can't be set to NULL. */
5809 if (!render_target
&& !render_target_idx
)
5811 WARN("Trying to set render target 0 to NULL.\n");
5812 return WINED3DERR_INVALIDCALL
;
5815 if (render_target
&& !(((IWineD3DSurfaceImpl
*)render_target
)->resource
.usage
& WINED3DUSAGE_RENDERTARGET
))
5817 FIXME("Surface %p doesn't have render target usage.\n", render_target
);
5818 return WINED3DERR_INVALIDCALL
;
5821 if (render_target
) IWineD3DSurface_AddRef(render_target
);
5822 device
->render_targets
[render_target_idx
] = (IWineD3DSurfaceImpl
*)render_target
;
5823 /* Release after the assignment, to prevent device_resource_released()
5824 * from seeing the surface as still in use. */
5825 if (prev
) IWineD3DSurface_Release((IWineD3DSurface
*)prev
);
5827 /* Render target 0 is special. */
5828 if (!render_target_idx
&& set_viewport
)
5830 /* Set the viewport and scissor rectangles, if requested. Tests show
5831 * that stateblock recording is ignored, the change goes directly
5832 * into the primary stateblock. */
5833 device
->stateBlock
->state
.viewport
.Height
= device
->render_targets
[0]->currentDesc
.Height
;
5834 device
->stateBlock
->state
.viewport
.Width
= device
->render_targets
[0]->currentDesc
.Width
;
5835 device
->stateBlock
->state
.viewport
.X
= 0;
5836 device
->stateBlock
->state
.viewport
.Y
= 0;
5837 device
->stateBlock
->state
.viewport
.MaxZ
= 1.0f
;
5838 device
->stateBlock
->state
.viewport
.MinZ
= 0.0f
;
5839 IWineD3DDeviceImpl_MarkStateDirty(device
, STATE_VIEWPORT
);
5841 device
->stateBlock
->state
.scissor_rect
.top
= 0;
5842 device
->stateBlock
->state
.scissor_rect
.left
= 0;
5843 device
->stateBlock
->state
.scissor_rect
.right
= device
->stateBlock
->state
.viewport
.Width
;
5844 device
->stateBlock
->state
.scissor_rect
.bottom
= device
->stateBlock
->state
.viewport
.Height
;
5845 IWineD3DDeviceImpl_MarkStateDirty(device
, STATE_SCISSORRECT
);
5851 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice
*iface
, IWineD3DSurface
*depth_stencil
)
5853 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5854 IWineD3DSurfaceImpl
*tmp
;
5856 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This
, depth_stencil
, This
->depth_stencil
);
5858 if (This
->depth_stencil
== (IWineD3DSurfaceImpl
*)depth_stencil
)
5860 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5864 if (This
->depth_stencil
)
5866 if (This
->swapchains
[0]->presentParms
.Flags
& WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5867 || This
->depth_stencil
->flags
& SFLAG_DISCARD
)
5869 surface_modify_ds_location(This
->depth_stencil
, SFLAG_DS_DISCARDED
,
5870 This
->depth_stencil
->currentDesc
.Width
,
5871 This
->depth_stencil
->currentDesc
.Height
);
5872 if (This
->depth_stencil
== This
->onscreen_depth_stencil
)
5874 IWineD3DSurface_Release((IWineD3DSurface
*)This
->onscreen_depth_stencil
);
5875 This
->onscreen_depth_stencil
= NULL
;
5880 tmp
= This
->depth_stencil
;
5881 This
->depth_stencil
= (IWineD3DSurfaceImpl
*)depth_stencil
;
5882 if (This
->depth_stencil
) IWineD3DSurface_AddRef((IWineD3DSurface
*)This
->depth_stencil
);
5883 if (tmp
) IWineD3DSurface_Release((IWineD3DSurface
*)tmp
);
5885 if ((!tmp
&& depth_stencil
) || (!depth_stencil
&& tmp
))
5887 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5888 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ZENABLE
));
5889 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_STENCILENABLE
));
5890 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_STENCILWRITEMASK
));
5896 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice
*iface
,
5897 UINT XHotSpot
, UINT YHotSpot
, IWineD3DSurface
*cursor_image
)
5899 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5900 IWineD3DSurfaceImpl
*s
= (IWineD3DSurfaceImpl
*)cursor_image
;
5901 WINED3DLOCKED_RECT lockedRect
;
5903 TRACE("iface %p, hotspot_x %u, hotspot_y %u, cursor_image %p.\n",
5904 iface
, XHotSpot
, YHotSpot
, cursor_image
);
5906 /* some basic validation checks */
5907 if (This
->cursorTexture
)
5909 struct wined3d_context
*context
= context_acquire(This
, NULL
);
5911 glDeleteTextures(1, &This
->cursorTexture
);
5913 context_release(context
);
5914 This
->cursorTexture
= 0;
5917 if ((s
->currentDesc
.Width
== 32) && (s
->currentDesc
.Height
== 32))
5918 This
->haveHardwareCursor
= TRUE
;
5920 This
->haveHardwareCursor
= FALSE
;
5924 WINED3DLOCKED_RECT rect
;
5926 /* MSDN: Cursor must be A8R8G8B8 */
5927 if (s
->resource
.format
->id
!= WINED3DFMT_B8G8R8A8_UNORM
)
5929 WARN("surface %p has an invalid format.\n", cursor_image
);
5930 return WINED3DERR_INVALIDCALL
;
5933 /* MSDN: Cursor must be smaller than the display mode */
5934 if (s
->currentDesc
.Width
> This
->ddraw_width
5935 || s
->currentDesc
.Height
> This
->ddraw_height
)
5937 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
5938 s
, s
->currentDesc
.Width
, s
->currentDesc
.Height
, This
->ddraw_width
, This
->ddraw_height
);
5939 return WINED3DERR_INVALIDCALL
;
5942 if (!This
->haveHardwareCursor
) {
5943 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5945 /* Do not store the surface's pointer because the application may
5946 * release it after setting the cursor image. Windows doesn't
5947 * addref the set surface, so we can't do this either without
5948 * creating circular refcount dependencies. Copy out the gl texture
5951 This
->cursorWidth
= s
->currentDesc
.Width
;
5952 This
->cursorHeight
= s
->currentDesc
.Height
;
5953 if (SUCCEEDED(IWineD3DSurface_Map(cursor_image
, &rect
, NULL
, WINED3DLOCK_READONLY
)))
5955 const struct wined3d_gl_info
*gl_info
= &This
->adapter
->gl_info
;
5956 const struct wined3d_format
*format
= wined3d_get_format(gl_info
, WINED3DFMT_B8G8R8A8_UNORM
);
5957 struct wined3d_context
*context
;
5958 char *mem
, *bits
= rect
.pBits
;
5959 GLint intfmt
= format
->glInternal
;
5960 GLint gl_format
= format
->glFormat
;
5961 GLint type
= format
->glType
;
5962 INT height
= This
->cursorHeight
;
5963 INT width
= This
->cursorWidth
;
5964 INT bpp
= format
->byte_count
;
5968 /* Reformat the texture memory (pitch and width can be
5970 mem
= HeapAlloc(GetProcessHeap(), 0, width
* height
* bpp
);
5971 for(i
= 0; i
< height
; i
++)
5972 memcpy(&mem
[width
* bpp
* i
], &bits
[rect
.Pitch
* i
], width
* bpp
);
5973 IWineD3DSurface_Unmap(cursor_image
);
5975 context
= context_acquire(This
, NULL
);
5979 if (gl_info
->supported
[APPLE_CLIENT_STORAGE
])
5981 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
5982 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5985 /* Make sure that a proper texture unit is selected */
5986 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
5987 checkGLcall("glActiveTextureARB");
5988 sampler
= This
->rev_tex_unit_map
[0];
5989 if (sampler
!= WINED3D_UNMAPPED_STAGE
)
5991 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(sampler
));
5993 /* Create a new cursor texture */
5994 glGenTextures(1, &This
->cursorTexture
);
5995 checkGLcall("glGenTextures");
5996 glBindTexture(GL_TEXTURE_2D
, This
->cursorTexture
);
5997 checkGLcall("glBindTexture");
5998 /* Copy the bitmap memory into the cursor texture */
5999 glTexImage2D(GL_TEXTURE_2D
, 0, intfmt
, width
, height
, 0, gl_format
, type
, mem
);
6000 checkGLcall("glTexImage2D");
6001 HeapFree(GetProcessHeap(), 0, mem
);
6003 if (gl_info
->supported
[APPLE_CLIENT_STORAGE
])
6005 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
6006 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6011 context_release(context
);
6015 FIXME("A cursor texture was not returned.\n");
6016 This
->cursorTexture
= 0;
6021 /* Draw a hardware cursor */
6022 ICONINFO cursorInfo
;
6024 /* Create and clear maskBits because it is not needed for
6025 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6027 DWORD
*maskBits
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
6028 (s
->currentDesc
.Width
* s
->currentDesc
.Height
/ 8));
6029 IWineD3DSurface_Map(cursor_image
, &lockedRect
, NULL
,
6030 WINED3DLOCK_NO_DIRTY_UPDATE
| WINED3DLOCK_READONLY
);
6031 TRACE("width: %u height: %u.\n", s
->currentDesc
.Width
, s
->currentDesc
.Height
);
6033 cursorInfo
.fIcon
= FALSE
;
6034 cursorInfo
.xHotspot
= XHotSpot
;
6035 cursorInfo
.yHotspot
= YHotSpot
;
6036 cursorInfo
.hbmMask
= CreateBitmap(s
->currentDesc
.Width
, s
->currentDesc
.Height
, 1, 1, maskBits
);
6037 cursorInfo
.hbmColor
= CreateBitmap(s
->currentDesc
.Width
, s
->currentDesc
.Height
, 1, 32, lockedRect
.pBits
);
6038 IWineD3DSurface_Unmap(cursor_image
);
6039 /* Create our cursor and clean up. */
6040 cursor
= CreateIconIndirect(&cursorInfo
);
6042 if (cursorInfo
.hbmMask
) DeleteObject(cursorInfo
.hbmMask
);
6043 if (cursorInfo
.hbmColor
) DeleteObject(cursorInfo
.hbmColor
);
6044 if (This
->hardwareCursor
) DestroyCursor(This
->hardwareCursor
);
6045 This
->hardwareCursor
= cursor
;
6046 HeapFree(GetProcessHeap(), 0, maskBits
);
6050 This
->xHotSpot
= XHotSpot
;
6051 This
->yHotSpot
= YHotSpot
;
6055 static void WINAPI
IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice
*iface
,
6056 int XScreenSpace
, int YScreenSpace
, DWORD flags
)
6058 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6060 TRACE("iface %p, x %d, y %d, flags %#x.\n",
6061 iface
, XScreenSpace
, YScreenSpace
, flags
);
6063 This
->xScreenSpace
= XScreenSpace
;
6064 This
->yScreenSpace
= YScreenSpace
;
6067 static BOOL WINAPI
IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice
* iface
, BOOL bShow
) {
6068 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6069 BOOL oldVisible
= This
->bCursorVisible
;
6072 TRACE("(%p) : visible(%d)\n", This
, bShow
);
6075 * When ShowCursor is first called it should make the cursor appear at the OS's last
6076 * known cursor position. Because of this, some applications just repetitively call
6077 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6080 This
->xScreenSpace
= pt
.x
;
6081 This
->yScreenSpace
= pt
.y
;
6083 if (This
->haveHardwareCursor
) {
6084 This
->bCursorVisible
= bShow
;
6086 SetCursor(This
->hardwareCursor
);
6092 if (This
->cursorTexture
)
6093 This
->bCursorVisible
= bShow
;
6099 static HRESULT WINAPI
evict_managed_resource(IWineD3DResource
*resource
, void *data
) {
6100 TRACE("checking resource %p for eviction\n", resource
);
6101 if(((IWineD3DResourceImpl
*) resource
)->resource
.pool
== WINED3DPOOL_MANAGED
) {
6102 TRACE("Evicting %p\n", resource
);
6103 IWineD3DResource_UnLoad(resource
);
6105 IWineD3DResource_Release(resource
);
6109 static HRESULT WINAPI
IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice
*iface
)
6111 TRACE("iface %p.\n", iface
);
6113 IWineD3DDevice_EnumResources(iface
, evict_managed_resource
, NULL
);
6114 /* Invalidate stream sources, the buffer(s) may have been evicted. */
6115 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl
*)iface
, STATE_STREAMSRC
);
6120 static HRESULT
updateSurfaceDesc(IWineD3DSurfaceImpl
*surface
, const WINED3DPRESENT_PARAMETERS
* pPresentationParameters
)
6122 IWineD3DDeviceImpl
*device
= surface
->resource
.device
;
6123 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
6125 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6126 if (surface
->flags
& SFLAG_DIBSECTION
)
6128 /* Release the DC */
6129 SelectObject(surface
->hDC
, surface
->dib
.holdbitmap
);
6130 DeleteDC(surface
->hDC
);
6131 /* Release the DIB section */
6132 DeleteObject(surface
->dib
.DIBsection
);
6133 surface
->dib
.bitmap_data
= NULL
;
6134 surface
->resource
.allocatedMemory
= NULL
;
6135 surface
->flags
&= ~SFLAG_DIBSECTION
;
6137 surface
->currentDesc
.Width
= pPresentationParameters
->BackBufferWidth
;
6138 surface
->currentDesc
.Height
= pPresentationParameters
->BackBufferHeight
;
6139 if (gl_info
->supported
[ARB_TEXTURE_NON_POWER_OF_TWO
] || gl_info
->supported
[ARB_TEXTURE_RECTANGLE
]
6140 || gl_info
->supported
[WINED3D_GL_NORMALIZED_TEXRECT
])
6142 surface
->pow2Width
= pPresentationParameters
->BackBufferWidth
;
6143 surface
->pow2Height
= pPresentationParameters
->BackBufferHeight
;
6145 surface
->pow2Width
= surface
->pow2Height
= 1;
6146 while (surface
->pow2Width
< pPresentationParameters
->BackBufferWidth
) surface
->pow2Width
<<= 1;
6147 while (surface
->pow2Height
< pPresentationParameters
->BackBufferHeight
) surface
->pow2Height
<<= 1;
6150 if (surface
->texture_name
)
6152 struct wined3d_context
*context
= context_acquire(device
, NULL
);
6154 glDeleteTextures(1, &surface
->texture_name
);
6156 context_release(context
);
6157 surface
->texture_name
= 0;
6158 surface
->flags
&= ~SFLAG_CLIENT
;
6160 if (surface
->pow2Width
!= pPresentationParameters
->BackBufferWidth
6161 || surface
->pow2Height
!= pPresentationParameters
->BackBufferHeight
)
6163 surface
->flags
|= SFLAG_NONPOW2
;
6167 surface
->flags
&= ~SFLAG_NONPOW2
;
6169 HeapFree(GetProcessHeap(), 0, surface
->resource
.heapMemory
);
6170 surface
->resource
.allocatedMemory
= NULL
;
6171 surface
->resource
.heapMemory
= NULL
;
6172 surface
->resource
.size
= IWineD3DSurface_GetPitch((IWineD3DSurface
*) surface
) * surface
->pow2Width
;
6174 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6176 if (!surface_init_sysmem(surface
))
6178 return E_OUTOFMEMORY
;
6183 static HRESULT WINAPI
reset_unload_resources(IWineD3DResource
*resource
, void *data
) {
6184 TRACE("Unloading resource %p\n", resource
);
6185 IWineD3DResource_UnLoad(resource
);
6186 IWineD3DResource_Release(resource
);
6190 static BOOL
is_display_mode_supported(IWineD3DDeviceImpl
*This
, const WINED3DPRESENT_PARAMETERS
*pp
)
6193 WINED3DDISPLAYMODE m
;
6196 /* All Windowed modes are supported, as is leaving the current mode */
6197 if(pp
->Windowed
) return TRUE
;
6198 if(!pp
->BackBufferWidth
) return TRUE
;
6199 if(!pp
->BackBufferHeight
) return TRUE
;
6201 count
= wined3d_get_adapter_mode_count(This
->wined3d
, This
->adapter
->ordinal
, WINED3DFMT_UNKNOWN
);
6202 for (i
= 0; i
< count
; ++i
)
6204 memset(&m
, 0, sizeof(m
));
6205 hr
= wined3d_enum_adapter_modes(This
->wined3d
, This
->adapter
->ordinal
, WINED3DFMT_UNKNOWN
, i
, &m
);
6207 ERR("Failed to enumerate adapter mode.\n");
6208 if (m
.Width
== pp
->BackBufferWidth
&& m
.Height
== pp
->BackBufferHeight
)
6209 /* Mode found, it is supported. */
6212 /* Mode not found -> not supported */
6216 /* Do not call while under the GL lock. */
6217 static void delete_opengl_contexts(IWineD3DDeviceImpl
*device
, IWineD3DSwapChainImpl
*swapchain
)
6219 const struct wined3d_gl_info
*gl_info
;
6220 struct wined3d_context
*context
;
6221 IWineD3DBaseShaderImpl
*shader
;
6223 context
= context_acquire(device
, NULL
);
6224 gl_info
= context
->gl_info
;
6226 IWineD3DDevice_EnumResources((IWineD3DDevice
*)device
, reset_unload_resources
, NULL
);
6227 LIST_FOR_EACH_ENTRY(shader
, &device
->shaders
, IWineD3DBaseShaderImpl
, baseShader
.shader_list_entry
)
6229 device
->shader_backend
->shader_destroy(shader
);
6233 if (device
->depth_blt_texture
)
6235 glDeleteTextures(1, &device
->depth_blt_texture
);
6236 device
->depth_blt_texture
= 0;
6238 if (device
->depth_blt_rb
)
6240 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &device
->depth_blt_rb
);
6241 device
->depth_blt_rb
= 0;
6242 device
->depth_blt_rb_w
= 0;
6243 device
->depth_blt_rb_h
= 0;
6247 device
->blitter
->free_private(device
);
6248 device
->frag_pipe
->free_private(device
);
6249 device
->shader_backend
->shader_free_private(device
);
6250 destroy_dummy_textures(device
, gl_info
);
6252 context_release(context
);
6254 while (device
->numContexts
)
6256 context_destroy(device
, device
->contexts
[0]);
6258 HeapFree(GetProcessHeap(), 0, swapchain
->context
);
6259 swapchain
->context
= NULL
;
6260 swapchain
->num_contexts
= 0;
6263 /* Do not call while under the GL lock. */
6264 static HRESULT
create_primary_opengl_context(IWineD3DDeviceImpl
*device
, IWineD3DSwapChainImpl
*swapchain
)
6266 struct wined3d_context
*context
;
6268 IWineD3DSurfaceImpl
*target
;
6270 /* Recreate the primary swapchain's context */
6271 swapchain
->context
= HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain
->context
));
6272 if (!swapchain
->context
)
6274 ERR("Failed to allocate memory for swapchain context array.\n");
6275 return E_OUTOFMEMORY
;
6278 target
= swapchain
->back_buffers
? swapchain
->back_buffers
[0] : swapchain
->front_buffer
;
6279 if (!(context
= context_create(swapchain
, target
, swapchain
->ds_format
)))
6281 WARN("Failed to create context.\n");
6282 HeapFree(GetProcessHeap(), 0, swapchain
->context
);
6286 swapchain
->context
[0] = context
;
6287 swapchain
->num_contexts
= 1;
6288 create_dummy_textures(device
);
6289 context_release(context
);
6291 hr
= device
->shader_backend
->shader_alloc_private(device
);
6294 ERR("Failed to allocate shader private data, hr %#x.\n", hr
);
6298 hr
= device
->frag_pipe
->alloc_private(device
);
6301 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr
);
6302 device
->shader_backend
->shader_free_private(device
);
6306 hr
= device
->blitter
->alloc_private(device
);
6309 ERR("Failed to allocate blitter private data, hr %#x.\n", hr
);
6310 device
->frag_pipe
->free_private(device
);
6311 device
->shader_backend
->shader_free_private(device
);
6318 context_acquire(device
, NULL
);
6319 destroy_dummy_textures(device
, context
->gl_info
);
6320 context_release(context
);
6321 context_destroy(device
, context
);
6322 HeapFree(GetProcessHeap(), 0, swapchain
->context
);
6323 swapchain
->num_contexts
= 0;
6327 /* Do not call while under the GL lock. */
6328 static HRESULT WINAPI
IWineD3DDeviceImpl_Reset(IWineD3DDevice
*iface
,
6329 WINED3DPRESENT_PARAMETERS
*pPresentationParameters
)
6331 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6332 IWineD3DSwapChainImpl
*swapchain
;
6334 BOOL DisplayModeChanged
= FALSE
;
6335 WINED3DDISPLAYMODE mode
;
6336 TRACE("(%p)\n", This
);
6338 hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**) &swapchain
);
6340 ERR("Failed to get the first implicit swapchain\n");
6344 if(!is_display_mode_supported(This
, pPresentationParameters
)) {
6345 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6346 WARN("Requested mode: %d, %d\n", pPresentationParameters
->BackBufferWidth
,
6347 pPresentationParameters
->BackBufferHeight
);
6348 IWineD3DSwapChain_Release((IWineD3DSwapChain
*)swapchain
);
6349 return WINED3DERR_INVALIDCALL
;
6352 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6353 * on an existing gl context, so there's no real need for recreation.
6355 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6357 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6359 TRACE("New params:\n");
6360 TRACE("BackBufferWidth = %d\n", pPresentationParameters
->BackBufferWidth
);
6361 TRACE("BackBufferHeight = %d\n", pPresentationParameters
->BackBufferHeight
);
6362 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters
->BackBufferFormat
));
6363 TRACE("BackBufferCount = %d\n", pPresentationParameters
->BackBufferCount
);
6364 TRACE("MultiSampleType = %d\n", pPresentationParameters
->MultiSampleType
);
6365 TRACE("MultiSampleQuality = %d\n", pPresentationParameters
->MultiSampleQuality
);
6366 TRACE("SwapEffect = %d\n", pPresentationParameters
->SwapEffect
);
6367 TRACE("hDeviceWindow = %p\n", pPresentationParameters
->hDeviceWindow
);
6368 TRACE("Windowed = %s\n", pPresentationParameters
->Windowed
? "true" : "false");
6369 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters
->EnableAutoDepthStencil
? "true" : "false");
6370 TRACE("Flags = %08x\n", pPresentationParameters
->Flags
);
6371 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters
->FullScreen_RefreshRateInHz
);
6372 TRACE("PresentationInterval = %d\n", pPresentationParameters
->PresentationInterval
);
6374 /* No special treatment of these parameters. Just store them */
6375 swapchain
->presentParms
.SwapEffect
= pPresentationParameters
->SwapEffect
;
6376 swapchain
->presentParms
.Flags
= pPresentationParameters
->Flags
;
6377 swapchain
->presentParms
.PresentationInterval
= pPresentationParameters
->PresentationInterval
;
6378 swapchain
->presentParms
.FullScreen_RefreshRateInHz
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
6380 /* What to do about these? */
6381 if (pPresentationParameters
->BackBufferCount
6382 && pPresentationParameters
->BackBufferCount
!= swapchain
->presentParms
.BackBufferCount
)
6383 ERR("Cannot change the back buffer count yet\n");
6385 if(pPresentationParameters
->BackBufferFormat
!= WINED3DFMT_UNKNOWN
&&
6386 pPresentationParameters
->BackBufferFormat
!= swapchain
->presentParms
.BackBufferFormat
) {
6387 ERR("Cannot change the back buffer format yet\n");
6390 if (pPresentationParameters
->hDeviceWindow
6391 && pPresentationParameters
->hDeviceWindow
!= swapchain
->presentParms
.hDeviceWindow
)
6392 ERR("Cannot change the device window yet\n");
6394 if (pPresentationParameters
->EnableAutoDepthStencil
&& !This
->auto_depth_stencil
)
6398 TRACE("Creating the depth stencil buffer\n");
6400 hrc
= IWineD3DDeviceParent_CreateDepthStencilSurface(This
->device_parent
,
6401 pPresentationParameters
->BackBufferWidth
,
6402 pPresentationParameters
->BackBufferHeight
,
6403 pPresentationParameters
->AutoDepthStencilFormat
,
6404 pPresentationParameters
->MultiSampleType
,
6405 pPresentationParameters
->MultiSampleQuality
,
6407 (IWineD3DSurface
**)&This
->auto_depth_stencil
);
6410 ERR("Failed to create the depth stencil buffer\n");
6411 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
6412 return WINED3DERR_INVALIDCALL
;
6416 if (This
->onscreen_depth_stencil
)
6418 IWineD3DSurface_Release((IWineD3DSurface
*)This
->onscreen_depth_stencil
);
6419 This
->onscreen_depth_stencil
= NULL
;
6422 /* Reset the depth stencil */
6423 if (pPresentationParameters
->EnableAutoDepthStencil
)
6424 IWineD3DDevice_SetDepthStencilSurface(iface
, (IWineD3DSurface
*)This
->auto_depth_stencil
);
6426 IWineD3DDevice_SetDepthStencilSurface(iface
, NULL
);
6428 TRACE("Resetting stateblock\n");
6429 wined3d_stateblock_decref(This
->updateStateBlock
);
6430 wined3d_stateblock_decref(This
->stateBlock
);
6432 delete_opengl_contexts(This
, swapchain
);
6434 if(pPresentationParameters
->Windowed
) {
6435 mode
.Width
= swapchain
->orig_width
;
6436 mode
.Height
= swapchain
->orig_height
;
6437 mode
.RefreshRate
= 0;
6438 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
6440 mode
.Width
= pPresentationParameters
->BackBufferWidth
;
6441 mode
.Height
= pPresentationParameters
->BackBufferHeight
;
6442 mode
.RefreshRate
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
6443 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
6446 /* Should Width == 800 && Height == 0 set 800x600? */
6447 if (pPresentationParameters
->BackBufferWidth
&& pPresentationParameters
->BackBufferHeight
6448 && (pPresentationParameters
->BackBufferWidth
!= swapchain
->presentParms
.BackBufferWidth
6449 || pPresentationParameters
->BackBufferHeight
!= swapchain
->presentParms
.BackBufferHeight
))
6453 if(!pPresentationParameters
->Windowed
) {
6454 DisplayModeChanged
= TRUE
;
6456 swapchain
->presentParms
.BackBufferWidth
= pPresentationParameters
->BackBufferWidth
;
6457 swapchain
->presentParms
.BackBufferHeight
= pPresentationParameters
->BackBufferHeight
;
6459 hr
= updateSurfaceDesc(swapchain
->front_buffer
, pPresentationParameters
);
6462 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
6466 for (i
= 0; i
< swapchain
->presentParms
.BackBufferCount
; ++i
)
6468 hr
= updateSurfaceDesc(swapchain
->back_buffers
[i
], pPresentationParameters
);
6471 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
6475 if (This
->auto_depth_stencil
)
6477 hr
= updateSurfaceDesc(This
->auto_depth_stencil
, pPresentationParameters
);
6480 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
6486 if (!pPresentationParameters
->Windowed
!= !swapchain
->presentParms
.Windowed
6487 || DisplayModeChanged
)
6489 BOOL filter
= This
->filter_messages
;
6490 This
->filter_messages
= TRUE
;
6492 IWineD3DDevice_SetDisplayMode(iface
, 0, &mode
);
6494 if (!pPresentationParameters
->Windowed
)
6496 if (swapchain
->presentParms
.Windowed
)
6498 HWND focus_window
= This
->createParms
.hFocusWindow
;
6499 if (!focus_window
) focus_window
= pPresentationParameters
->hDeviceWindow
;
6500 if (FAILED(hr
= IWineD3DDevice_AcquireFocusWindow(iface
, focus_window
)))
6502 ERR("Failed to acquire focus window, hr %#x.\n", hr
);
6503 IWineD3DSwapChain_Release((IWineD3DSwapChain
*)swapchain
);
6507 /* switch from windowed to fs */
6508 IWineD3DDevice_SetupFullscreenWindow(iface
, swapchain
->device_window
,
6509 pPresentationParameters
->BackBufferWidth
,
6510 pPresentationParameters
->BackBufferHeight
);
6514 /* Fullscreen -> fullscreen mode change */
6515 MoveWindow(swapchain
->device_window
, 0, 0,
6516 pPresentationParameters
->BackBufferWidth
, pPresentationParameters
->BackBufferHeight
,
6520 else if (!swapchain
->presentParms
.Windowed
)
6522 /* Fullscreen -> windowed switch */
6523 IWineD3DDevice_RestoreFullscreenWindow(iface
, swapchain
->device_window
);
6524 IWineD3DDevice_ReleaseFocusWindow(iface
);
6526 swapchain
->presentParms
.Windowed
= pPresentationParameters
->Windowed
;
6528 This
->filter_messages
= filter
;
6530 else if (!pPresentationParameters
->Windowed
)
6532 DWORD style
= This
->style
, exStyle
= This
->exStyle
;
6533 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6534 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6535 * Reset to clear up their mess. Guild Wars also loses the device during that.
6539 IWineD3DDevice_SetupFullscreenWindow(iface
, swapchain
->device_window
,
6540 pPresentationParameters
->BackBufferWidth
,
6541 pPresentationParameters
->BackBufferHeight
);
6542 This
->style
= style
;
6543 This
->exStyle
= exStyle
;
6546 /* Note: No parent needed for initial internal stateblock */
6547 hr
= IWineD3DDevice_CreateStateBlock(iface
, WINED3DSBT_INIT
, &This
->stateBlock
);
6548 if (FAILED(hr
)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr
);
6549 else TRACE("Created stateblock %p\n", This
->stateBlock
);
6550 This
->updateStateBlock
= This
->stateBlock
;
6551 wined3d_stateblock_incref(This
->updateStateBlock
);
6553 stateblock_init_default_state(This
->stateBlock
);
6555 if(wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
)
6558 GetClientRect(swapchain
->win_handle
, &client_rect
);
6560 if(!swapchain
->presentParms
.BackBufferCount
)
6562 TRACE("Single buffered rendering\n");
6563 swapchain
->render_to_fbo
= FALSE
;
6565 else if(swapchain
->presentParms
.BackBufferWidth
!= client_rect
.right
||
6566 swapchain
->presentParms
.BackBufferHeight
!= client_rect
.bottom
)
6568 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6569 swapchain
->presentParms
.BackBufferWidth
,
6570 swapchain
->presentParms
.BackBufferHeight
,
6571 client_rect
.right
, client_rect
.bottom
);
6572 swapchain
->render_to_fbo
= TRUE
;
6576 TRACE("Rendering directly to GL_BACK\n");
6577 swapchain
->render_to_fbo
= FALSE
;
6581 hr
= create_primary_opengl_context(This
, swapchain
);
6582 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
6584 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6590 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice
*iface
, BOOL enable_dialogs
)
6592 TRACE("iface %p, enable_dialogs %#x.\n", iface
, enable_dialogs
);
6594 if (!enable_dialogs
) FIXME("Dialogs cannot be disabled yet.\n");
6600 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice
*iface
, WINED3DDEVICE_CREATION_PARAMETERS
*pParameters
) {
6601 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6602 TRACE("(%p) : pParameters %p\n", This
, pParameters
);
6604 *pParameters
= This
->createParms
;
6608 static void WINAPI
IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice
*iface
,
6609 UINT iSwapChain
, DWORD flags
, const WINED3DGAMMARAMP
*pRamp
)
6611 IWineD3DSwapChain
*swapchain
;
6613 TRACE("Relaying to swapchain\n");
6615 if (IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
) == WINED3D_OK
)
6617 IWineD3DSwapChain_SetGammaRamp(swapchain
, flags
, pRamp
);
6618 IWineD3DSwapChain_Release(swapchain
);
6622 static void WINAPI
IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DGAMMARAMP
* pRamp
) {
6623 IWineD3DSwapChain
*swapchain
;
6625 TRACE("Relaying to swapchain\n");
6627 if (IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
) == WINED3D_OK
) {
6628 IWineD3DSwapChain_GetGammaRamp(swapchain
, pRamp
);
6629 IWineD3DSwapChain_Release(swapchain
);
6633 void device_resource_add(struct IWineD3DDeviceImpl
*device
, struct IWineD3DResourceImpl
*resource
)
6635 TRACE("device %p, resource %p.\n", device
, resource
);
6637 list_add_head(&device
->resources
, &resource
->resource
.resource_list_entry
);
6640 static void device_resource_remove(struct IWineD3DDeviceImpl
*device
, struct IWineD3DResourceImpl
*resource
)
6642 TRACE("device %p, resource %p.\n", device
, resource
);
6644 list_remove(&resource
->resource
.resource_list_entry
);
6647 void device_resource_released(struct IWineD3DDeviceImpl
*device
, struct IWineD3DResourceImpl
*resource
)
6649 WINED3DRESOURCETYPE type
= IWineD3DResource_GetType((IWineD3DResource
*)resource
);
6652 TRACE("device %p, resource %p, type %s.\n", device
, resource
, debug_d3dresourcetype(type
));
6654 context_resource_released(device
, resource
, type
);
6658 case WINED3DRTYPE_SURFACE
:
6659 if (!device
->d3d_initialized
) break;
6661 for (i
= 0; i
< device
->adapter
->gl_info
.limits
.buffers
; ++i
)
6663 if (device
->render_targets
[i
] == (IWineD3DSurfaceImpl
*)resource
)
6665 ERR("Surface %p is still in use as render target %u.\n", resource
, i
);
6666 device
->render_targets
[i
] = NULL
;
6670 if (device
->depth_stencil
== (IWineD3DSurfaceImpl
*)resource
)
6672 ERR("Surface %p is still in use as depth/stencil buffer.\n", resource
);
6673 device
->depth_stencil
= NULL
;
6677 case WINED3DRTYPE_TEXTURE
:
6678 case WINED3DRTYPE_CUBETEXTURE
:
6679 case WINED3DRTYPE_VOLUMETEXTURE
:
6680 for (i
= 0; i
< MAX_COMBINED_SAMPLERS
; ++i
)
6682 if (device
->stateBlock
&& device
->stateBlock
->state
.textures
[i
] == (IWineD3DBaseTextureImpl
*)resource
)
6684 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6685 resource
, device
->stateBlock
, i
);
6686 device
->stateBlock
->state
.textures
[i
] = NULL
;
6689 if (device
->updateStateBlock
!= device
->stateBlock
6690 && device
->updateStateBlock
->state
.textures
[i
] == (IWineD3DBaseTextureImpl
*)resource
)
6692 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6693 resource
, device
->updateStateBlock
, i
);
6694 device
->updateStateBlock
->state
.textures
[i
] = NULL
;
6699 case WINED3DRTYPE_BUFFER
:
6700 for (i
= 0; i
< MAX_STREAMS
; ++i
)
6702 if (device
->stateBlock
6703 && device
->stateBlock
->state
.streams
[i
].buffer
== (struct wined3d_buffer
*)resource
)
6705 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6706 resource
, device
->stateBlock
, i
);
6707 device
->stateBlock
->state
.streams
[i
].buffer
= NULL
;
6710 if (device
->updateStateBlock
!= device
->stateBlock
6711 && device
->updateStateBlock
->state
.streams
[i
].buffer
== (struct wined3d_buffer
*)resource
)
6713 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6714 resource
, device
->updateStateBlock
, i
);
6715 device
->updateStateBlock
->state
.streams
[i
].buffer
= NULL
;
6720 if (device
->stateBlock
&& device
->stateBlock
->state
.index_buffer
== (struct wined3d_buffer
*)resource
)
6722 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6723 resource
, device
->stateBlock
);
6724 device
->stateBlock
->state
.index_buffer
= NULL
;
6727 if (device
->updateStateBlock
!= device
->stateBlock
6728 && device
->updateStateBlock
->state
.index_buffer
== (struct wined3d_buffer
*)resource
)
6730 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6731 resource
, device
->updateStateBlock
);
6732 device
->updateStateBlock
->state
.index_buffer
= NULL
;
6740 /* Remove the resource from the resourceStore */
6741 device_resource_remove(device
, resource
);
6743 TRACE("Resource released.\n");
6746 static HRESULT WINAPI
IWineD3DDeviceImpl_EnumResources(IWineD3DDevice
*iface
, D3DCB_ENUMRESOURCES pCallback
, void *pData
) {
6747 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6748 IWineD3DResourceImpl
*resource
, *cursor
;
6750 TRACE("(%p)->(%p,%p)\n", This
, pCallback
, pData
);
6752 LIST_FOR_EACH_ENTRY_SAFE(resource
, cursor
, &This
->resources
, IWineD3DResourceImpl
, resource
.resource_list_entry
) {
6753 TRACE("enumerating resource %p\n", resource
);
6754 IWineD3DResource_AddRef((IWineD3DResource
*) resource
);
6755 ret
= pCallback((IWineD3DResource
*) resource
, pData
);
6756 if(ret
== S_FALSE
) {
6757 TRACE("Canceling enumeration\n");
6764 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice
*iface
, HDC dc
, IWineD3DSurface
**surface
)
6766 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6767 IWineD3DResourceImpl
*resource
;
6769 LIST_FOR_EACH_ENTRY(resource
, &This
->resources
, IWineD3DResourceImpl
, resource
.resource_list_entry
)
6771 WINED3DRESOURCETYPE type
= IWineD3DResource_GetType((IWineD3DResource
*)resource
);
6772 if (type
== WINED3DRTYPE_SURFACE
)
6774 if (((IWineD3DSurfaceImpl
*)resource
)->hDC
== dc
)
6776 TRACE("Found surface %p for dc %p.\n", resource
, dc
);
6777 *surface
= (IWineD3DSurface
*)resource
;
6783 return WINED3DERR_INVALIDCALL
;
6786 /**********************************************************
6787 * IWineD3DDevice VTbl follows
6788 **********************************************************/
6790 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl
=
6792 /*** IUnknown methods ***/
6793 IWineD3DDeviceImpl_QueryInterface
,
6794 IWineD3DDeviceImpl_AddRef
,
6795 IWineD3DDeviceImpl_Release
,
6796 /*** IWineD3DDevice methods ***/
6797 /*** Creation methods**/
6798 IWineD3DDeviceImpl_CreateBuffer
,
6799 IWineD3DDeviceImpl_CreateVertexBuffer
,
6800 IWineD3DDeviceImpl_CreateIndexBuffer
,
6801 IWineD3DDeviceImpl_CreateStateBlock
,
6802 IWineD3DDeviceImpl_CreateSurface
,
6803 IWineD3DDeviceImpl_CreateRendertargetView
,
6804 IWineD3DDeviceImpl_CreateTexture
,
6805 IWineD3DDeviceImpl_CreateVolumeTexture
,
6806 IWineD3DDeviceImpl_CreateVolume
,
6807 IWineD3DDeviceImpl_CreateCubeTexture
,
6808 IWineD3DDeviceImpl_CreateQuery
,
6809 IWineD3DDeviceImpl_CreateSwapChain
,
6810 IWineD3DDeviceImpl_CreateVertexDeclaration
,
6811 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF
,
6812 IWineD3DDeviceImpl_CreateVertexShader
,
6813 IWineD3DDeviceImpl_CreateGeometryShader
,
6814 IWineD3DDeviceImpl_CreatePixelShader
,
6815 IWineD3DDeviceImpl_CreatePalette
,
6816 /*** Odd functions **/
6817 IWineD3DDeviceImpl_Init3D
,
6818 IWineD3DDeviceImpl_InitGDI
,
6819 IWineD3DDeviceImpl_Uninit3D
,
6820 IWineD3DDeviceImpl_UninitGDI
,
6821 IWineD3DDeviceImpl_SetMultithreaded
,
6822 IWineD3DDeviceImpl_EvictManagedResources
,
6823 IWineD3DDeviceImpl_GetAvailableTextureMem
,
6824 IWineD3DDeviceImpl_GetBackBuffer
,
6825 IWineD3DDeviceImpl_GetCreationParameters
,
6826 IWineD3DDeviceImpl_GetDeviceCaps
,
6827 IWineD3DDeviceImpl_GetDirect3D
,
6828 IWineD3DDeviceImpl_GetDisplayMode
,
6829 IWineD3DDeviceImpl_SetDisplayMode
,
6830 IWineD3DDeviceImpl_GetNumberOfSwapChains
,
6831 IWineD3DDeviceImpl_GetRasterStatus
,
6832 IWineD3DDeviceImpl_GetSwapChain
,
6833 IWineD3DDeviceImpl_Reset
,
6834 IWineD3DDeviceImpl_SetDialogBoxMode
,
6835 IWineD3DDeviceImpl_SetCursorProperties
,
6836 IWineD3DDeviceImpl_SetCursorPosition
,
6837 IWineD3DDeviceImpl_ShowCursor
,
6838 /*** Getters and setters **/
6839 IWineD3DDeviceImpl_SetClipPlane
,
6840 IWineD3DDeviceImpl_GetClipPlane
,
6841 IWineD3DDeviceImpl_SetClipStatus
,
6842 IWineD3DDeviceImpl_GetClipStatus
,
6843 IWineD3DDeviceImpl_SetCurrentTexturePalette
,
6844 IWineD3DDeviceImpl_GetCurrentTexturePalette
,
6845 IWineD3DDeviceImpl_SetDepthStencilSurface
,
6846 IWineD3DDeviceImpl_GetDepthStencilSurface
,
6847 IWineD3DDeviceImpl_SetGammaRamp
,
6848 IWineD3DDeviceImpl_GetGammaRamp
,
6849 IWineD3DDeviceImpl_SetIndexBuffer
,
6850 IWineD3DDeviceImpl_GetIndexBuffer
,
6851 IWineD3DDeviceImpl_SetBaseVertexIndex
,
6852 IWineD3DDeviceImpl_GetBaseVertexIndex
,
6853 IWineD3DDeviceImpl_SetLight
,
6854 IWineD3DDeviceImpl_GetLight
,
6855 IWineD3DDeviceImpl_SetLightEnable
,
6856 IWineD3DDeviceImpl_GetLightEnable
,
6857 IWineD3DDeviceImpl_SetMaterial
,
6858 IWineD3DDeviceImpl_GetMaterial
,
6859 IWineD3DDeviceImpl_SetNPatchMode
,
6860 IWineD3DDeviceImpl_GetNPatchMode
,
6861 IWineD3DDeviceImpl_SetPaletteEntries
,
6862 IWineD3DDeviceImpl_GetPaletteEntries
,
6863 IWineD3DDeviceImpl_SetPixelShader
,
6864 IWineD3DDeviceImpl_GetPixelShader
,
6865 IWineD3DDeviceImpl_SetPixelShaderConstantB
,
6866 IWineD3DDeviceImpl_GetPixelShaderConstantB
,
6867 IWineD3DDeviceImpl_SetPixelShaderConstantI
,
6868 IWineD3DDeviceImpl_GetPixelShaderConstantI
,
6869 IWineD3DDeviceImpl_SetPixelShaderConstantF
,
6870 IWineD3DDeviceImpl_GetPixelShaderConstantF
,
6871 IWineD3DDeviceImpl_SetRenderState
,
6872 IWineD3DDeviceImpl_GetRenderState
,
6873 IWineD3DDeviceImpl_SetRenderTarget
,
6874 IWineD3DDeviceImpl_GetRenderTarget
,
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
,
6936 IWineD3DDeviceImpl_SetupFullscreenWindow
,
6937 IWineD3DDeviceImpl_RestoreFullscreenWindow
,
6940 HRESULT
device_init(IWineD3DDeviceImpl
*device
, struct wined3d
*wined3d
,
6941 UINT adapter_idx
, WINED3DDEVTYPE device_type
, HWND focus_window
, DWORD flags
,
6942 IWineD3DDeviceParent
*device_parent
)
6944 struct wined3d_adapter
*adapter
= &wined3d
->adapters
[adapter_idx
];
6945 const struct fragment_pipeline
*fragment_pipeline
;
6946 struct shader_caps shader_caps
;
6947 struct fragment_caps ffp_caps
;
6948 WINED3DDISPLAYMODE mode
;
6952 device
->lpVtbl
= &IWineD3DDevice_Vtbl
;
6954 device
->wined3d
= wined3d
;
6955 wined3d_incref(device
->wined3d
);
6956 device
->adapter
= wined3d
->adapter_count
? adapter
: NULL
;
6957 device
->device_parent
= device_parent
;
6958 list_init(&device
->resources
);
6959 list_init(&device
->shaders
);
6961 device
->surface_alignment
= wined3d
->dxVersion
== 7 ? DDRAW_PITCH_ALIGNMENT
: D3D8_PITCH_ALIGNMENT
;
6963 /* Get the initial screen setup for ddraw. */
6964 hr
= wined3d_get_adapter_display_mode(wined3d
, adapter_idx
, &mode
);
6967 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr
);
6968 wined3d_decref(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 if (device
->shader_backend
)
6989 device
->shader_backend
->shader_get_caps(&adapter
->gl_info
, &shader_caps
);
6990 device
->d3d_vshader_constantF
= shader_caps
.MaxVertexShaderConst
;
6991 device
->d3d_pshader_constantF
= shader_caps
.MaxPixelShaderConst
;
6992 device
->vs_clipping
= shader_caps
.VSClipping
;
6994 fragment_pipeline
= adapter
->fragment_pipe
;
6995 device
->frag_pipe
= fragment_pipeline
;
6996 if (fragment_pipeline
)
6998 fragment_pipeline
->get_caps(&adapter
->gl_info
, &ffp_caps
);
6999 device
->max_ffp_textures
= ffp_caps
.MaxSimultaneousTextures
;
7001 hr
= compile_state_table(device
->StateTable
, device
->multistate_funcs
, &adapter
->gl_info
,
7002 ffp_vertexstate_template
, fragment_pipeline
, misc_state_template
);
7005 ERR("Failed to compile state table, hr %#x.\n", hr
);
7006 wined3d_decref(device
->wined3d
);
7010 device
->blitter
= adapter
->blitter
;
7016 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl
*This
, DWORD state
) {
7017 DWORD rep
= This
->StateTable
[state
].representative
;
7018 struct wined3d_context
*context
;
7023 for(i
= 0; i
< This
->numContexts
; i
++) {
7024 context
= This
->contexts
[i
];
7025 if(isStateDirty(context
, rep
)) continue;
7027 context
->dirtyArray
[context
->numDirtyEntries
++] = rep
;
7028 idx
= rep
/ (sizeof(*context
->isStateDirty
) * CHAR_BIT
);
7029 shift
= rep
& ((sizeof(*context
->isStateDirty
) * CHAR_BIT
) - 1);
7030 context
->isStateDirty
[idx
] |= (1 << shift
);
7034 void get_drawable_size_fbo(struct wined3d_context
*context
, UINT
*width
, UINT
*height
)
7036 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7037 *width
= context
->current_rt
->pow2Width
;
7038 *height
= context
->current_rt
->pow2Height
;
7041 void get_drawable_size_backbuffer(struct wined3d_context
*context
, UINT
*width
, UINT
*height
)
7043 IWineD3DSwapChainImpl
*swapchain
= context
->swapchain
;
7044 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7045 * current context's drawable, which is the size of the back buffer of the swapchain
7046 * the active context belongs to. */
7047 *width
= swapchain
->presentParms
.BackBufferWidth
;
7048 *height
= swapchain
->presentParms
.BackBufferHeight
;
7051 LRESULT
device_process_message(IWineD3DDeviceImpl
*device
, HWND window
, BOOL unicode
,
7052 UINT message
, WPARAM wparam
, LPARAM lparam
, WNDPROC proc
)
7054 if (device
->filter_messages
)
7056 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7057 window
, message
, wparam
, lparam
);
7059 return DefWindowProcW(window
, message
, wparam
, lparam
);
7061 return DefWindowProcA(window
, message
, wparam
, lparam
);
7064 if (message
== WM_DESTROY
)
7066 TRACE("unregister window %p.\n", window
);
7067 wined3d_unregister_window(window
);
7069 if (device
->focus_window
== window
) device
->focus_window
= NULL
;
7070 else ERR("Window %p is not the focus window for device %p.\n", window
, device
);
7074 return CallWindowProcW(proc
, window
, message
, wparam
, lparam
);
7076 return CallWindowProcA(proc
, window
, message
, wparam
, lparam
);