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
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d
);
36 #define GLINFO_LOCATION This->adapter->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light
= {
41 WINED3DLIGHT_DIRECTIONAL
, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
54 /* static function declarations */
55 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice
*iface
, IWineD3DResource
*resource
);
57 /**********************************************************
58 * Global variable / Constants follow
59 **********************************************************/
60 const float identity
[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
62 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
63 * actually have the same values in GL and D3D. */
64 static GLenum
gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type
)
66 switch(primitive_type
)
68 case WINED3DPT_POINTLIST
:
71 case WINED3DPT_LINELIST
:
74 case WINED3DPT_LINESTRIP
:
77 case WINED3DPT_TRIANGLELIST
:
80 case WINED3DPT_TRIANGLESTRIP
:
81 return GL_TRIANGLE_STRIP
;
83 case WINED3DPT_TRIANGLEFAN
:
84 return GL_TRIANGLE_FAN
;
86 case WINED3DPT_LINELIST_ADJ
:
87 return GL_LINES_ADJACENCY_ARB
;
89 case WINED3DPT_LINESTRIP_ADJ
:
90 return GL_LINE_STRIP_ADJACENCY_ARB
;
92 case WINED3DPT_TRIANGLELIST_ADJ
:
93 return GL_TRIANGLES_ADJACENCY_ARB
;
95 case WINED3DPT_TRIANGLESTRIP_ADJ
:
96 return GL_TRIANGLE_STRIP_ADJACENCY_ARB
;
99 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type
));
104 static WINED3DPRIMITIVETYPE
d3d_primitive_type_from_gl(GLenum primitive_type
)
106 switch(primitive_type
)
109 return WINED3DPT_POINTLIST
;
112 return WINED3DPT_LINELIST
;
115 return WINED3DPT_LINESTRIP
;
118 return WINED3DPT_TRIANGLELIST
;
120 case GL_TRIANGLE_STRIP
:
121 return WINED3DPT_TRIANGLESTRIP
;
123 case GL_TRIANGLE_FAN
:
124 return WINED3DPT_TRIANGLEFAN
;
126 case GL_LINES_ADJACENCY_ARB
:
127 return WINED3DPT_LINELIST_ADJ
;
129 case GL_LINE_STRIP_ADJACENCY_ARB
:
130 return WINED3DPT_LINESTRIP_ADJ
;
132 case GL_TRIANGLES_ADJACENCY_ARB
:
133 return WINED3DPT_TRIANGLELIST_ADJ
;
135 case GL_TRIANGLE_STRIP_ADJACENCY_ARB
:
136 return WINED3DPT_TRIANGLESTRIP_ADJ
;
139 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type
));
140 return WINED3DPT_UNDEFINED
;
144 static BOOL
fixed_get_input(BYTE usage
, BYTE usage_idx
, unsigned int *regnum
)
146 if ((usage
== WINED3DDECLUSAGE_POSITION
|| usage
== WINED3DDECLUSAGE_POSITIONT
) && usage_idx
== 0)
147 *regnum
= WINED3D_FFP_POSITION
;
148 else if (usage
== WINED3DDECLUSAGE_BLENDWEIGHT
&& usage_idx
== 0)
149 *regnum
= WINED3D_FFP_BLENDWEIGHT
;
150 else if (usage
== WINED3DDECLUSAGE_BLENDINDICES
&& usage_idx
== 0)
151 *regnum
= WINED3D_FFP_BLENDINDICES
;
152 else if (usage
== WINED3DDECLUSAGE_NORMAL
&& usage_idx
== 0)
153 *regnum
= WINED3D_FFP_NORMAL
;
154 else if (usage
== WINED3DDECLUSAGE_PSIZE
&& usage_idx
== 0)
155 *regnum
= WINED3D_FFP_PSIZE
;
156 else if (usage
== WINED3DDECLUSAGE_COLOR
&& usage_idx
== 0)
157 *regnum
= WINED3D_FFP_DIFFUSE
;
158 else if (usage
== WINED3DDECLUSAGE_COLOR
&& usage_idx
== 1)
159 *regnum
= WINED3D_FFP_SPECULAR
;
160 else if (usage
== WINED3DDECLUSAGE_TEXCOORD
&& usage_idx
< WINED3DDP_MAXTEXCOORD
)
161 *regnum
= WINED3D_FFP_TEXCOORD0
+ usage_idx
;
164 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage
), usage_idx
);
172 void device_stream_info_from_declaration(IWineD3DDeviceImpl
*This
,
173 BOOL use_vshader
, struct wined3d_stream_info
*stream_info
, BOOL
*fixup
)
175 /* We need to deal with frequency data! */
176 IWineD3DVertexDeclarationImpl
*declaration
= (IWineD3DVertexDeclarationImpl
*)This
->stateBlock
->vertexDecl
;
177 UINT stream_count
= This
->stateBlock
->streamIsUP
? 0 : declaration
->num_streams
;
178 const DWORD
*streams
= declaration
->streams
;
181 memset(stream_info
, 0, sizeof(*stream_info
));
183 /* Check for transformed vertices, disable vertex shader if present. */
184 stream_info
->position_transformed
= declaration
->position_transformed
;
185 if (declaration
->position_transformed
) use_vshader
= FALSE
;
187 /* Translate the declaration into strided data. */
188 for (i
= 0; i
< declaration
->element_count
; ++i
)
190 const struct wined3d_vertex_declaration_element
*element
= &declaration
->elements
[i
];
191 GLuint buffer_object
= 0;
192 const BYTE
*data
= NULL
;
197 TRACE("%p Element %p (%u of %u)\n", declaration
->elements
,
198 element
, i
+ 1, declaration
->element_count
);
200 if (!This
->stateBlock
->streamSource
[element
->input_slot
]) continue;
202 stride
= This
->stateBlock
->streamStride
[element
->input_slot
];
203 if (This
->stateBlock
->streamIsUP
)
205 TRACE("Stream %u is UP, %p\n", element
->input_slot
, This
->stateBlock
->streamSource
[element
->input_slot
]);
207 data
= (BYTE
*)This
->stateBlock
->streamSource
[element
->input_slot
];
211 TRACE("Stream %u isn't UP, %p\n", element
->input_slot
, This
->stateBlock
->streamSource
[element
->input_slot
]);
212 data
= buffer_get_memory(This
->stateBlock
->streamSource
[element
->input_slot
], 0, &buffer_object
);
214 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
215 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
216 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
217 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
218 * not, drawStridedSlow is needed, including a vertex buffer path. */
219 if (This
->stateBlock
->loadBaseVertexIndex
< 0)
221 WARN("loadBaseVertexIndex is < 0 (%d), not using vbos\n", This
->stateBlock
->loadBaseVertexIndex
);
223 data
= ((struct wined3d_buffer
*)This
->stateBlock
->streamSource
[element
->input_slot
])->resource
.allocatedMemory
;
224 if ((UINT_PTR
)data
< -This
->stateBlock
->loadBaseVertexIndex
* stride
)
226 FIXME("System memory vertex data load offset is negative!\n");
232 if (buffer_object
) *fixup
= TRUE
;
233 else if (*fixup
&& !use_vshader
234 && (element
->usage
== WINED3DDECLUSAGE_COLOR
235 || element
->usage
== WINED3DDECLUSAGE_POSITIONT
))
237 static BOOL warned
= FALSE
;
240 /* This may be bad with the fixed function pipeline. */
241 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
247 data
+= element
->offset
;
249 TRACE("offset %u input_slot %u usage_idx %d\n", element
->offset
, element
->input_slot
, element
->usage_idx
);
253 if (element
->output_slot
== ~0U)
255 /* TODO: Assuming vertexdeclarations are usually used with the
256 * same or a similar shader, it might be worth it to store the
257 * last used output slot and try that one first. */
258 stride_used
= vshader_get_input(This
->stateBlock
->vertexShader
,
259 element
->usage
, element
->usage_idx
, &idx
);
263 idx
= element
->output_slot
;
269 if (!element
->ffp_valid
)
271 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
272 debug_d3dformat(element
->format_desc
->format
), debug_d3ddeclusage(element
->usage
));
277 stride_used
= fixed_get_input(element
->usage
, element
->usage_idx
, &idx
);
283 TRACE("Load %s array %u [usage %s, usage_idx %u, "
284 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
285 use_vshader
? "shader": "fixed function", idx
,
286 debug_d3ddeclusage(element
->usage
), element
->usage_idx
, element
->input_slot
,
287 element
->offset
, stride
, debug_d3dformat(element
->format_desc
->format
), buffer_object
);
289 stream_info
->elements
[idx
].format_desc
= element
->format_desc
;
290 stream_info
->elements
[idx
].stride
= stride
;
291 stream_info
->elements
[idx
].data
= data
;
292 stream_info
->elements
[idx
].stream_idx
= element
->input_slot
;
293 stream_info
->elements
[idx
].buffer_object
= buffer_object
;
295 if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA
) && element
->format_desc
->format
== WINED3DFMT_A8R8G8B8
)
297 stream_info
->swizzle_map
|= 1 << idx
;
299 stream_info
->use_map
|= 1 << idx
;
303 /* Now call PreLoad on all the vertex buffers. In the very rare case
304 * that the buffers stopps converting PreLoad will dirtify the VDECL again.
305 * The vertex buffer can now use the strided structure in the device instead of finding its
308 * NULL streams won't be recorded in the array, UP streams won't be either. A stream is only
310 for (i
= 0; i
< stream_count
; ++i
)
312 IWineD3DBuffer
*vb
= This
->stateBlock
->streamSource
[streams
[i
]];
313 if (vb
) IWineD3DBuffer_PreLoad(vb
);
317 static void stream_info_element_from_strided(IWineD3DDeviceImpl
*This
,
318 const struct WineDirect3DStridedData
*strided
, struct wined3d_stream_info_element
*e
)
320 const struct GlPixelFormatDesc
*format_desc
= getFormatDescEntry(strided
->format
, &This
->adapter
->gl_info
);
321 e
->format_desc
= format_desc
;
322 e
->stride
= strided
->dwStride
;
323 e
->data
= strided
->lpData
;
325 e
->buffer_object
= 0;
328 void device_stream_info_from_strided(IWineD3DDeviceImpl
*This
,
329 const struct WineDirect3DVertexStridedData
*strided
, struct wined3d_stream_info
*stream_info
)
333 memset(stream_info
, 0, sizeof(*stream_info
));
335 if (strided
->position
.lpData
)
336 stream_info_element_from_strided(This
, &strided
->position
, &stream_info
->elements
[WINED3D_FFP_POSITION
]);
337 if (strided
->normal
.lpData
)
338 stream_info_element_from_strided(This
, &strided
->normal
, &stream_info
->elements
[WINED3D_FFP_NORMAL
]);
339 if (strided
->diffuse
.lpData
)
340 stream_info_element_from_strided(This
, &strided
->diffuse
, &stream_info
->elements
[WINED3D_FFP_DIFFUSE
]);
341 if (strided
->specular
.lpData
)
342 stream_info_element_from_strided(This
, &strided
->specular
, &stream_info
->elements
[WINED3D_FFP_SPECULAR
]);
344 for (i
= 0; i
< WINED3DDP_MAXTEXCOORD
; ++i
)
346 if (strided
->texCoords
[i
].lpData
)
347 stream_info_element_from_strided(This
, &strided
->texCoords
[i
],
348 &stream_info
->elements
[WINED3D_FFP_TEXCOORD0
+ i
]);
351 stream_info
->position_transformed
= strided
->position_transformed
;
353 for (i
= 0; i
< sizeof(stream_info
->elements
) / sizeof(*stream_info
->elements
); ++i
)
355 if (!stream_info
->elements
[i
].format_desc
) continue;
357 if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA
) && stream_info
->elements
[i
].format_desc
->format
== WINED3DFMT_A8R8G8B8
)
359 stream_info
->swizzle_map
|= 1 << i
;
361 stream_info
->use_map
|= 1 << i
;
365 /**********************************************************
366 * IUnknown parts follows
367 **********************************************************/
369 static HRESULT WINAPI
IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice
*iface
,REFIID riid
,LPVOID
*ppobj
)
371 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
373 TRACE("(%p)->(%s,%p)\n",This
,debugstr_guid(riid
),ppobj
);
374 if (IsEqualGUID(riid
, &IID_IUnknown
)
375 || IsEqualGUID(riid
, &IID_IWineD3DBase
)
376 || IsEqualGUID(riid
, &IID_IWineD3DDevice
)) {
377 IUnknown_AddRef(iface
);
382 return E_NOINTERFACE
;
385 static ULONG WINAPI
IWineD3DDeviceImpl_AddRef(IWineD3DDevice
*iface
) {
386 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
387 ULONG refCount
= InterlockedIncrement(&This
->ref
);
389 TRACE("(%p) : AddRef increasing from %d\n", This
, refCount
- 1);
393 static ULONG WINAPI
IWineD3DDeviceImpl_Release(IWineD3DDevice
*iface
) {
394 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
395 ULONG refCount
= InterlockedDecrement(&This
->ref
);
397 TRACE("(%p) : Releasing from %d\n", This
, refCount
+ 1);
402 for (i
= 0; i
< sizeof(This
->multistate_funcs
)/sizeof(This
->multistate_funcs
[0]); ++i
) {
403 HeapFree(GetProcessHeap(), 0, This
->multistate_funcs
[i
]);
404 This
->multistate_funcs
[i
] = NULL
;
407 /* TODO: Clean up all the surfaces and textures! */
408 /* NOTE: You must release the parent if the object was created via a callback
409 ** ***************************/
411 if (!list_empty(&This
->resources
)) {
412 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This
);
413 dumpResources(&This
->resources
);
416 if(This
->contexts
) ERR("Context array not freed!\n");
417 if (This
->hardwareCursor
) DestroyCursor(This
->hardwareCursor
);
418 This
->haveHardwareCursor
= FALSE
;
420 IWineD3D_Release(This
->wineD3D
);
421 This
->wineD3D
= NULL
;
422 HeapFree(GetProcessHeap(), 0, This
);
423 TRACE("Freed device %p\n", This
);
429 /**********************************************************
430 * IWineD3DDevice implementation follows
431 **********************************************************/
432 static HRESULT WINAPI
IWineD3DDeviceImpl_GetParent(IWineD3DDevice
*iface
, IUnknown
**pParent
) {
433 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
434 *pParent
= This
->parent
;
435 IUnknown_AddRef(This
->parent
);
439 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice
*iface
,
440 struct wined3d_buffer_desc
*desc
, const void *data
, IUnknown
*parent
, IWineD3DBuffer
**buffer
)
442 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
443 struct wined3d_buffer
*object
;
446 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface
, desc
, data
, parent
, buffer
);
448 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
451 ERR("Failed to allocate memory\n");
452 return E_OUTOFMEMORY
;
455 object
->vtbl
= &wined3d_buffer_vtbl
;
456 object
->desc
= *desc
;
458 FIXME("Ignoring access flags (pool)\n");
460 hr
= resource_init(&object
->resource
, WINED3DRTYPE_BUFFER
, This
, desc
->byte_width
,
461 desc
->usage
, WINED3DFMT_UNKNOWN
, WINED3DPOOL_MANAGED
, parent
);
464 WARN("Failed to initialize resource, returning %#x\n", hr
);
465 HeapFree(GetProcessHeap(), 0, object
);
468 object
->buffer_type_hint
= GL_ARRAY_BUFFER_ARB
;
470 TRACE("Created resource %p\n", object
);
472 IWineD3DDeviceImpl_AddResource(iface
, (IWineD3DResource
*)object
);
474 TRACE("size %#x, usage=%#x, format %s, memory @ %p, iface @ %p\n", object
->resource
.size
, object
->resource
.usage
,
475 debug_d3dformat(object
->resource
.format_desc
->format
), object
->resource
.allocatedMemory
, object
);
481 hr
= IWineD3DBuffer_Map((IWineD3DBuffer
*)object
, 0, desc
->byte_width
, &ptr
, 0);
484 ERR("Failed to map buffer, hr %#x\n", hr
);
485 IWineD3DBuffer_Release((IWineD3DBuffer
*)object
);
489 memcpy(ptr
, data
, desc
->byte_width
);
491 hr
= IWineD3DBuffer_Unmap((IWineD3DBuffer
*)object
);
494 ERR("Failed to unmap buffer, hr %#x\n", hr
);
495 IWineD3DBuffer_Release((IWineD3DBuffer
*)object
);
500 *buffer
= (IWineD3DBuffer
*)object
;
505 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice
*iface
, UINT Size
, DWORD Usage
,
506 DWORD FVF
, WINED3DPOOL Pool
, IWineD3DBuffer
**ppVertexBuffer
, IUnknown
*parent
)
508 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
509 /* Dummy format for now */
510 const struct GlPixelFormatDesc
*format_desc
= getFormatDescEntry(WINED3DFMT_VERTEXDATA
, &This
->adapter
->gl_info
);
511 struct wined3d_buffer
*object
;
512 int dxVersion
= ( (IWineD3DImpl
*) This
->wineD3D
)->dxVersion
;
517 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
518 *ppVertexBuffer
= NULL
;
519 return WINED3DERR_INVALIDCALL
;
520 } else if(Pool
== WINED3DPOOL_SCRATCH
) {
521 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
522 * anyway, SCRATCH vertex buffers aren't usable anywhere
524 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
525 *ppVertexBuffer
= NULL
;
526 return WINED3DERR_INVALIDCALL
;
529 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
532 ERR("Out of memory\n");
533 *ppVertexBuffer
= NULL
;
534 return WINED3DERR_OUTOFVIDEOMEMORY
;
537 object
->vtbl
= &wined3d_buffer_vtbl
;
538 hr
= resource_init(&object
->resource
, WINED3DRTYPE_BUFFER
, This
, Size
, Usage
, format_desc
, Pool
, parent
);
541 WARN("Failed to initialize resource, returning %#x\n", hr
);
542 HeapFree(GetProcessHeap(), 0, object
);
543 *ppVertexBuffer
= NULL
;
546 object
->buffer_type_hint
= GL_ARRAY_BUFFER_ARB
;
548 TRACE("(%p) : Created resource %p\n", This
, object
);
550 IWineD3DDeviceImpl_AddResource(iface
, (IWineD3DResource
*)object
);
552 TRACE("(%p) : Size=%d, Usage=0x%08x, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This
, Size
, Usage
, FVF
, Pool
, object
->resource
.allocatedMemory
, object
);
553 *ppVertexBuffer
= (IWineD3DBuffer
*)object
;
555 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
556 * drawStridedFast (half-life 2).
558 * Basically converting the vertices in the buffer is quite expensive, and observations
559 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
560 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
562 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
563 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
564 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
565 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
567 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
568 * more. In this call we can convert dx7 buffers too.
570 conv
= ((FVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) || (FVF
& (WINED3DFVF_DIFFUSE
| WINED3DFVF_SPECULAR
));
571 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT
)) {
572 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
573 } else if(Pool
== WINED3DPOOL_SYSTEMMEM
) {
574 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
575 } else if(Usage
& WINED3DUSAGE_DYNAMIC
) {
576 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
577 } else if(dxVersion
<= 7 && conv
) {
578 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
580 object
->flags
|= WINED3D_BUFFER_CREATEBO
;
585 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice
*iface
,
586 UINT Length
, DWORD Usage
, WINED3DPOOL Pool
, IWineD3DBuffer
**ppIndexBuffer
, IUnknown
*parent
)
588 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
589 const struct GlPixelFormatDesc
*format_desc
= getFormatDescEntry(WINED3DFMT_UNKNOWN
, &This
->adapter
->gl_info
);
590 struct wined3d_buffer
*object
;
593 TRACE("(%p) Creating index buffer\n", This
);
595 /* Allocate the storage for the device */
596 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
599 ERR("Out of memory\n");
600 *ppIndexBuffer
= NULL
;
601 return WINED3DERR_OUTOFVIDEOMEMORY
;
604 object
->vtbl
= &wined3d_buffer_vtbl
;
605 hr
= resource_init(&object
->resource
, WINED3DRTYPE_BUFFER
, This
, Length
, Usage
, format_desc
, Pool
, parent
);
608 WARN("Failed to initialize resource, returning %#x\n", hr
);
609 HeapFree(GetProcessHeap(), 0, object
);
610 *ppIndexBuffer
= NULL
;
613 object
->buffer_type_hint
= GL_ELEMENT_ARRAY_BUFFER_ARB
;
615 TRACE("(%p) : Created resource %p\n", This
, object
);
617 IWineD3DDeviceImpl_AddResource(iface
, (IWineD3DResource
*)object
);
619 if(Pool
!= WINED3DPOOL_SYSTEMMEM
&& !(Usage
& WINED3DUSAGE_DYNAMIC
) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT
)) {
620 object
->flags
|= WINED3D_BUFFER_CREATEBO
;
623 TRACE("(%p) : Len=%d, Use=%x, Pool=%d - Memory@%p, Iface@%p\n", This
, Length
, Usage
,
624 Pool
, object
, object
->resource
.allocatedMemory
);
625 *ppIndexBuffer
= (IWineD3DBuffer
*) object
;
630 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice
* iface
, WINED3DSTATEBLOCKTYPE Type
, IWineD3DStateBlock
** ppStateBlock
, IUnknown
*parent
) {
632 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
633 IWineD3DStateBlockImpl
*object
;
637 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
640 ERR("Out of memory\n");
641 *ppStateBlock
= NULL
;
642 return WINED3DERR_OUTOFVIDEOMEMORY
;
645 object
->lpVtbl
= &IWineD3DStateBlock_Vtbl
;
646 object
->wineD3DDevice
= This
;
647 object
->parent
= parent
;
649 object
->blockType
= Type
;
651 *ppStateBlock
= (IWineD3DStateBlock
*)object
;
653 for(i
= 0; i
< LIGHTMAP_SIZE
; i
++) {
654 list_init(&object
->lightMap
[i
]);
657 temp_result
= allocate_shader_constants(object
);
658 if (FAILED(temp_result
))
660 HeapFree(GetProcessHeap(), 0, object
);
664 /* Special case - Used during initialization to produce a placeholder stateblock
665 so other functions called can update a state block */
666 if (Type
== WINED3DSBT_INIT
|| Type
== WINED3DSBT_RECORDED
)
668 /* Don't bother increasing the reference count otherwise a device will never
669 be freed due to circular dependencies */
673 /* Otherwise, might as well set the whole state block to the appropriate values */
674 if (This
->stateBlock
!= NULL
)
675 stateblock_copy((IWineD3DStateBlock
*) object
, (IWineD3DStateBlock
*) This
->stateBlock
);
677 memset(object
->streamFreq
, 1, sizeof(object
->streamFreq
));
679 /* Reset the ref and type after kludging it */
680 object
->wineD3DDevice
= This
;
682 object
->blockType
= Type
;
684 TRACE("Updating changed flags appropriate for type %d\n", Type
);
686 if (Type
== WINED3DSBT_ALL
) {
688 TRACE("ALL => Pretend everything has changed\n");
689 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, TRUE
);
691 /* Lights are not part of the changed / set structure */
692 for(j
= 0; j
< LIGHTMAP_SIZE
; j
++) {
694 LIST_FOR_EACH(e
, &object
->lightMap
[j
]) {
695 PLIGHTINFOEL
*light
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
696 light
->changed
= TRUE
;
697 light
->enabledChanged
= TRUE
;
700 for(j
= 1; j
<= WINEHIGHEST_RENDER_STATE
; j
++) {
701 object
->contained_render_states
[j
- 1] = j
;
703 object
->num_contained_render_states
= WINEHIGHEST_RENDER_STATE
;
704 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
705 for(j
= 1; j
<= HIGHEST_TRANSFORMSTATE
; j
++) {
706 object
->contained_transform_states
[j
- 1] = j
;
708 object
->num_contained_transform_states
= HIGHEST_TRANSFORMSTATE
;
709 for(j
= 0; j
< GL_LIMITS(vshader_constantsF
); j
++) {
710 object
->contained_vs_consts_f
[j
] = j
;
712 object
->num_contained_vs_consts_f
= GL_LIMITS(vshader_constantsF
);
713 for(j
= 0; j
< MAX_CONST_I
; j
++) {
714 object
->contained_vs_consts_i
[j
] = j
;
716 object
->num_contained_vs_consts_i
= MAX_CONST_I
;
717 for(j
= 0; j
< MAX_CONST_B
; j
++) {
718 object
->contained_vs_consts_b
[j
] = j
;
720 object
->num_contained_vs_consts_b
= MAX_CONST_B
;
721 for(j
= 0; j
< GL_LIMITS(pshader_constantsF
); j
++) {
722 object
->contained_ps_consts_f
[j
] = j
;
724 object
->num_contained_ps_consts_f
= GL_LIMITS(pshader_constantsF
);
725 for(j
= 0; j
< MAX_CONST_I
; j
++) {
726 object
->contained_ps_consts_i
[j
] = j
;
728 object
->num_contained_ps_consts_i
= MAX_CONST_I
;
729 for(j
= 0; j
< MAX_CONST_B
; j
++) {
730 object
->contained_ps_consts_b
[j
] = j
;
732 object
->num_contained_ps_consts_b
= MAX_CONST_B
;
733 for(i
= 0; i
< MAX_TEXTURES
; i
++) {
734 for (j
= 0; j
<= WINED3D_HIGHEST_TEXTURE_STATE
; ++j
)
736 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= i
;
737 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= j
;
738 object
->num_contained_tss_states
++;
741 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++) {
742 for(j
= 1; j
<= WINED3D_HIGHEST_SAMPLER_STATE
; j
++) {
743 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= i
;
744 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= j
;
745 object
->num_contained_sampler_states
++;
749 for(i
= 0; i
< MAX_STREAMS
; i
++) {
750 if(object
->streamSource
[i
]) {
751 IWineD3DBuffer_AddRef(object
->streamSource
[i
]);
754 if(object
->pIndexData
) {
755 IWineD3DBuffer_AddRef(object
->pIndexData
);
757 if(object
->vertexShader
) {
758 IWineD3DVertexShader_AddRef(object
->vertexShader
);
760 if(object
->pixelShader
) {
761 IWineD3DPixelShader_AddRef(object
->pixelShader
);
764 } else if (Type
== WINED3DSBT_PIXELSTATE
) {
766 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
767 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, FALSE
);
769 object
->changed
.pixelShader
= TRUE
;
771 /* Pixel Shader Constants */
772 for (i
= 0; i
< GL_LIMITS(pshader_constantsF
); ++i
) {
773 object
->contained_ps_consts_f
[i
] = i
;
774 object
->changed
.pixelShaderConstantsF
[i
] = TRUE
;
776 object
->num_contained_ps_consts_f
= GL_LIMITS(pshader_constantsF
);
777 for (i
= 0; i
< MAX_CONST_B
; ++i
) {
778 object
->contained_ps_consts_b
[i
] = i
;
779 object
->changed
.pixelShaderConstantsB
|= (1 << i
);
781 object
->num_contained_ps_consts_b
= MAX_CONST_B
;
782 for (i
= 0; i
< MAX_CONST_I
; ++i
) {
783 object
->contained_ps_consts_i
[i
] = i
;
784 object
->changed
.pixelShaderConstantsI
|= (1 << i
);
786 object
->num_contained_ps_consts_i
= MAX_CONST_I
;
788 for (i
= 0; i
< NUM_SAVEDPIXELSTATES_R
; i
++) {
789 DWORD rs
= SavedPixelStates_R
[i
];
790 object
->changed
.renderState
[rs
>> 5] |= 1 << (rs
& 0x1f);
791 object
->contained_render_states
[i
] = rs
;
793 object
->num_contained_render_states
= NUM_SAVEDPIXELSTATES_R
;
794 for (j
= 0; j
< MAX_TEXTURES
; j
++) {
795 for (i
= 0; i
< NUM_SAVEDPIXELSTATES_T
; i
++) {
796 DWORD state
= SavedPixelStates_T
[i
];
797 object
->changed
.textureState
[j
] |= 1 << state
;
798 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= j
;
799 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= state
;
800 object
->num_contained_tss_states
++;
803 for (j
= 0 ; j
< MAX_COMBINED_SAMPLERS
; j
++) {
804 for (i
=0; i
< NUM_SAVEDPIXELSTATES_S
;i
++) {
805 DWORD state
= SavedPixelStates_S
[i
];
806 object
->changed
.samplerState
[j
] |= 1 << state
;
807 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= j
;
808 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= state
;
809 object
->num_contained_sampler_states
++;
812 if(object
->pixelShader
) {
813 IWineD3DPixelShader_AddRef(object
->pixelShader
);
816 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
817 * on them. This makes releasing the buffer easier
819 for(i
= 0; i
< MAX_STREAMS
; i
++) {
820 object
->streamSource
[i
] = NULL
;
822 object
->pIndexData
= NULL
;
823 object
->vertexShader
= NULL
;
825 } else if (Type
== WINED3DSBT_VERTEXSTATE
) {
827 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
828 stateblock_savedstates_set((IWineD3DStateBlock
*) object
, &object
->changed
, FALSE
);
830 object
->changed
.vertexShader
= TRUE
;
832 /* Vertex Shader Constants */
833 for (i
= 0; i
< GL_LIMITS(vshader_constantsF
); ++i
) {
834 object
->changed
.vertexShaderConstantsF
[i
] = TRUE
;
835 object
->contained_vs_consts_f
[i
] = i
;
837 object
->num_contained_vs_consts_f
= GL_LIMITS(vshader_constantsF
);
838 for (i
= 0; i
< MAX_CONST_B
; ++i
) {
839 object
->contained_vs_consts_b
[i
] = i
;
840 object
->changed
.vertexShaderConstantsB
|= (1 << i
);
842 object
->num_contained_vs_consts_b
= MAX_CONST_B
;
843 for (i
= 0; i
< MAX_CONST_I
; ++i
) {
844 object
->contained_vs_consts_i
[i
] = i
;
845 object
->changed
.vertexShaderConstantsI
|= (1 << i
);
847 object
->num_contained_vs_consts_i
= MAX_CONST_I
;
848 for (i
= 0; i
< NUM_SAVEDVERTEXSTATES_R
; i
++) {
849 DWORD rs
= SavedVertexStates_R
[i
];
850 object
->changed
.renderState
[rs
>> 5] |= 1 << (rs
& 0x1f);
851 object
->contained_render_states
[i
] = rs
;
853 object
->num_contained_render_states
= NUM_SAVEDVERTEXSTATES_R
;
854 for (j
= 0; j
< MAX_TEXTURES
; j
++) {
855 for (i
= 0; i
< NUM_SAVEDVERTEXSTATES_T
; i
++) {
856 DWORD state
= SavedVertexStates_T
[i
];
857 object
->changed
.textureState
[j
] |= 1 << state
;
858 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= j
;
859 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= state
;
860 object
->num_contained_tss_states
++;
863 for (j
= 0 ; j
< MAX_COMBINED_SAMPLERS
; j
++){
864 for (i
=0; i
< NUM_SAVEDVERTEXSTATES_S
;i
++) {
865 DWORD state
= SavedVertexStates_S
[i
];
866 object
->changed
.samplerState
[j
] |= 1 << state
;
867 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= j
;
868 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= state
;
869 object
->num_contained_sampler_states
++;
873 for(j
= 0; j
< LIGHTMAP_SIZE
; j
++) {
875 LIST_FOR_EACH(e
, &object
->lightMap
[j
]) {
876 PLIGHTINFOEL
*light
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
877 light
->changed
= TRUE
;
878 light
->enabledChanged
= TRUE
;
882 for(i
= 0; i
< MAX_STREAMS
; i
++) {
883 if(object
->streamSource
[i
]) {
884 IWineD3DBuffer_AddRef(object
->streamSource
[i
]);
887 if(object
->vertexShader
) {
888 IWineD3DVertexShader_AddRef(object
->vertexShader
);
890 object
->pIndexData
= NULL
;
891 object
->pixelShader
= NULL
;
893 FIXME("Unrecognized state block type %d\n", Type
);
896 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This
, object
);
900 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice
*iface
,
901 UINT Width
, UINT Height
, WINED3DFORMAT Format
, BOOL Lockable
, BOOL Discard
, UINT Level
,
902 IWineD3DSurface
**ppSurface
, WINED3DRESOURCETYPE Type
, DWORD Usage
, WINED3DPOOL Pool
,
903 WINED3DMULTISAMPLE_TYPE MultiSample
, DWORD MultisampleQuality
, WINED3DSURFTYPE Impl
, IUnknown
*parent
)
905 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
906 IWineD3DSurfaceImpl
*object
; /*NOTE: impl ref allowed since this is a create function */
907 unsigned int Size
= 1;
908 const struct GlPixelFormatDesc
*glDesc
= getFormatDescEntry(Format
, &GLINFO_LOCATION
);
912 TRACE("(%p) Create surface\n",This
);
914 if(MultisampleQuality
> 0) {
915 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality
);
916 MultisampleQuality
=0;
919 /** FIXME: Check that the format is supported
921 *******************************/
923 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
924 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
926 *********************************/
927 mul_4w
= (Width
+ 3) & ~3;
928 mul_4h
= (Height
+ 3) & ~3;
929 if (WINED3DFMT_UNKNOWN
== Format
) {
931 } else if (Format
== WINED3DFMT_DXT1
) {
932 /* DXT1 is half byte per pixel */
933 Size
= (mul_4w
* glDesc
->byte_count
* mul_4h
) >> 1;
935 } else if (Format
== WINED3DFMT_DXT2
|| Format
== WINED3DFMT_DXT3
||
936 Format
== WINED3DFMT_DXT4
|| Format
== WINED3DFMT_DXT5
||
937 Format
== WINED3DFMT_ATI2N
) {
938 Size
= (mul_4w
* glDesc
->byte_count
* mul_4h
);
940 /* The pitch is a multiple of 4 bytes */
941 Size
= ((Width
* glDesc
->byte_count
) + This
->surface_alignment
- 1) & ~(This
->surface_alignment
- 1);
945 if(glDesc
->heightscale
!= 0.0) Size
*= glDesc
->heightscale
;
947 /** Create and initialise the surface resource **/
948 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
951 ERR("Out of memory\n");
953 return WINED3DERR_OUTOFVIDEOMEMORY
;
956 /* Look at the implementation and set the correct Vtable */
960 /* Check if a 3D adapter is available when creating gl surfaces */
963 ERR("OpenGL surfaces are not available without opengl\n");
964 HeapFree(GetProcessHeap(), 0, object
);
965 return WINED3DERR_NOTAVAILABLE
;
967 object
->lpVtbl
= &IWineD3DSurface_Vtbl
;
971 object
->lpVtbl
= &IWineGDISurface_Vtbl
;
975 /* To be sure to catch this */
976 ERR("Unknown requested surface implementation %d!\n", Impl
);
977 HeapFree(GetProcessHeap(), 0, object
);
978 return WINED3DERR_INVALIDCALL
;
981 hr
= resource_init(&object
->resource
, WINED3DRTYPE_SURFACE
, This
, Size
, Usage
, glDesc
, Pool
, parent
);
984 WARN("Failed to initialize resource, returning %#x\n", hr
);
985 HeapFree(GetProcessHeap(), 0, object
);
990 TRACE("(%p) : Created resource %p\n", This
, object
);
992 IWineD3DDeviceImpl_AddResource(iface
, (IWineD3DResource
*)object
);
994 *ppSurface
= (IWineD3DSurface
*)object
;
996 /* "Standalone" surface */
997 IWineD3DSurface_SetContainer((IWineD3DSurface
*)object
, NULL
);
999 object
->currentDesc
.Width
= Width
;
1000 object
->currentDesc
.Height
= Height
;
1001 object
->currentDesc
.MultiSampleType
= MultiSample
;
1002 object
->currentDesc
.MultiSampleQuality
= MultisampleQuality
;
1003 object
->glDescription
.level
= Level
;
1004 list_init(&object
->overlays
);
1007 object
->Flags
= SFLAG_NORMCOORD
; /* Default to normalized coords */
1008 object
->Flags
|= Discard
? SFLAG_DISCARD
: 0;
1009 object
->Flags
|= (WINED3DFMT_D16_LOCKABLE
== Format
) ? SFLAG_LOCKABLE
: 0;
1010 object
->Flags
|= Lockable
? SFLAG_LOCKABLE
: 0;
1012 TRACE("Pool %d %d %d %d\n",Pool
, WINED3DPOOL_DEFAULT
, WINED3DPOOL_MANAGED
, WINED3DPOOL_SYSTEMMEM
);
1014 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
1015 * this function is too deep to need to care about things like this.
1016 * Levels need to be checked too, and possibly Type since they all affect what can be done.
1017 * ****************************************/
1019 case WINED3DPOOL_SCRATCH
:
1021 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
1022 "which are mutually exclusive, setting lockable to TRUE\n");
1025 case WINED3DPOOL_SYSTEMMEM
:
1026 if(!Lockable
) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
1027 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
1028 case WINED3DPOOL_MANAGED
:
1029 if(Usage
== WINED3DUSAGE_DYNAMIC
) FIXME("Create surface called with a pool of MANAGED and a "
1030 "Usage of DYNAMIC which are mutually exclusive, not doing "
1031 "anything just telling you.\n");
1033 case WINED3DPOOL_DEFAULT
: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
1034 if(!(Usage
& WINED3DUSAGE_DYNAMIC
) && !(Usage
& WINED3DUSAGE_RENDERTARGET
)
1035 && !(Usage
&& WINED3DUSAGE_DEPTHSTENCIL
) && Lockable
)
1036 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
1039 FIXME("(%p) Unknown pool %d\n", This
, Pool
);
1043 if (Usage
& WINED3DUSAGE_RENDERTARGET
&& Pool
!= WINED3DPOOL_DEFAULT
) {
1044 FIXME("Trying to create a render target that isn't in the default pool\n");
1047 /* mark the texture as dirty so that it gets loaded first time around*/
1048 surface_add_dirty_rect(*ppSurface
, NULL
);
1049 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
1050 This
, Width
, Height
, Format
, debug_d3dformat(Format
),
1051 (WINED3DFMT_D16_LOCKABLE
== Format
), *ppSurface
, object
->resource
.allocatedMemory
, object
->resource
.size
);
1053 list_init(&object
->renderbuffers
);
1055 /* Call the private setup routine */
1056 hr
= IWineD3DSurface_PrivateSetup((IWineD3DSurface
*)object
);
1059 ERR("Private setup failed, returning %#x\n", hr
);
1060 IWineD3DSurface_Release(*ppSurface
);
1068 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice
*iface
,
1069 IWineD3DResource
*resource
, IUnknown
*parent
, IWineD3DRendertargetView
**rendertarget_view
)
1071 struct wined3d_rendertarget_view
*object
;
1073 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1076 ERR("Failed to allocate memory\n");
1077 return E_OUTOFMEMORY
;
1080 object
->vtbl
= &wined3d_rendertarget_view_vtbl
;
1081 object
->refcount
= 1;
1082 IWineD3DResource_AddRef(resource
);
1083 object
->resource
= resource
;
1084 object
->parent
= parent
;
1086 *rendertarget_view
= (IWineD3DRendertargetView
*)object
;
1091 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice
*iface
,
1092 UINT Width
, UINT Height
, UINT Levels
, DWORD Usage
, WINED3DFORMAT Format
,
1093 WINED3DPOOL Pool
, IWineD3DTexture
**ppTexture
, IUnknown
*parent
)
1095 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1096 const struct GlPixelFormatDesc
*format_desc
= getFormatDescEntry(Format
, &This
->adapter
->gl_info
);
1097 IWineD3DTextureImpl
*object
;
1102 unsigned int pow2Width
;
1103 unsigned int pow2Height
;
1105 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This
, Width
, Height
, Levels
, Usage
);
1106 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
1107 Format
, debug_d3dformat(Format
), Pool
, ppTexture
, parent
);
1109 /* TODO: It should only be possible to create textures for formats
1110 that are reported as supported */
1111 if (WINED3DFMT_UNKNOWN
>= Format
) {
1112 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
1113 return WINED3DERR_INVALIDCALL
;
1116 /* Non-power2 support */
1117 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO
))
1120 pow2Height
= Height
;
1124 /* Find the nearest pow2 match */
1125 pow2Width
= pow2Height
= 1;
1126 while (pow2Width
< Width
) pow2Width
<<= 1;
1127 while (pow2Height
< Height
) pow2Height
<<= 1;
1129 if (pow2Width
!= Width
|| pow2Height
!= Height
)
1133 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
1134 return WINED3DERR_INVALIDCALL
;
1140 /* Calculate levels for mip mapping */
1141 if (Usage
& WINED3DUSAGE_AUTOGENMIPMAP
)
1143 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP
))
1145 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1146 return WINED3DERR_INVALIDCALL
;
1151 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1152 return WINED3DERR_INVALIDCALL
;
1159 Levels
= wined3d_log2i(max(Width
, Height
)) + 1;
1160 TRACE("Calculated levels = %d\n", Levels
);
1163 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1166 ERR("Out of memory\n");
1168 return WINED3DERR_OUTOFVIDEOMEMORY
;
1171 object
->lpVtbl
= &IWineD3DTexture_Vtbl
;
1172 hr
= resource_init(&object
->resource
, WINED3DRTYPE_TEXTURE
, This
, 0, Usage
, format_desc
, Pool
, parent
);
1175 WARN("Failed to initialize resource, returning %#x\n", hr
);
1176 HeapFree(GetProcessHeap(), 0, object
);
1181 TRACE("(%p) : Created resource %p\n", This
, object
);
1183 IWineD3DDeviceImpl_AddResource(iface
, (IWineD3DResource
*)object
);
1185 *ppTexture
= (IWineD3DTexture
*)object
;
1187 basetexture_init(&object
->baseTexture
, Levels
, Usage
);
1189 if (object
->resource
.format_desc
->Flags
& WINED3DFMT_FLAG_FILTERING
)
1191 object
->baseTexture
.minMipLookup
= minMipLookup
;
1192 object
->baseTexture
.magLookup
= magLookup
;
1194 object
->baseTexture
.minMipLookup
= minMipLookup_noFilter
;
1195 object
->baseTexture
.magLookup
= magLookup_noFilter
;
1198 /** FIXME: add support for real non-power-two if it's provided by the video card **/
1199 /* Precalculated scaling for 'faked' non power of two texture coords.
1200 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
1201 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
1202 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
1204 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT
) && (Width
!= pow2Width
|| Height
!= pow2Height
)) {
1205 object
->baseTexture
.pow2Matrix
[0] = 1.0;
1206 object
->baseTexture
.pow2Matrix
[5] = 1.0;
1207 object
->baseTexture
.pow2Matrix
[10] = 1.0;
1208 object
->baseTexture
.pow2Matrix
[15] = 1.0;
1209 object
->target
= GL_TEXTURE_2D
;
1210 object
->cond_np2
= TRUE
;
1211 object
->baseTexture
.minMipLookup
= minMipLookup_noFilter
;
1212 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE
) &&
1213 (Width
!= pow2Width
|| Height
!= pow2Height
) &&
1214 !((Format
== WINED3DFMT_P8
) && GL_SUPPORT(EXT_PALETTED_TEXTURE
) && (wined3d_settings
.rendertargetlock_mode
== RTL_READTEX
|| wined3d_settings
.rendertargetlock_mode
== RTL_TEXTEX
)))
1216 if ((Width
!= 1) || (Height
!= 1)) {
1217 object
->baseTexture
.pow2Matrix_identity
= FALSE
;
1220 object
->baseTexture
.pow2Matrix
[0] = (float)Width
;
1221 object
->baseTexture
.pow2Matrix
[5] = (float)Height
;
1222 object
->baseTexture
.pow2Matrix
[10] = 1.0;
1223 object
->baseTexture
.pow2Matrix
[15] = 1.0;
1224 object
->target
= GL_TEXTURE_RECTANGLE_ARB
;
1225 object
->cond_np2
= TRUE
;
1226 object
->baseTexture
.minMipLookup
= minMipLookup_noFilter
;
1228 if ((Width
!= pow2Width
) || (Height
!= pow2Height
)) {
1229 object
->baseTexture
.pow2Matrix_identity
= FALSE
;
1230 object
->baseTexture
.pow2Matrix
[0] = (((float)Width
) / ((float)pow2Width
));
1231 object
->baseTexture
.pow2Matrix
[5] = (((float)Height
) / ((float)pow2Height
));
1233 object
->baseTexture
.pow2Matrix
[0] = 1.0;
1234 object
->baseTexture
.pow2Matrix
[5] = 1.0;
1237 object
->baseTexture
.pow2Matrix
[10] = 1.0;
1238 object
->baseTexture
.pow2Matrix
[15] = 1.0;
1239 object
->target
= GL_TEXTURE_2D
;
1240 object
->cond_np2
= FALSE
;
1242 TRACE(" xf(%f) yf(%f)\n", object
->baseTexture
.pow2Matrix
[0], object
->baseTexture
.pow2Matrix
[5]);
1244 /* Generate all the surfaces */
1247 for (i
= 0; i
< object
->baseTexture
.levels
; i
++)
1249 /* use the callback to create the texture surface */
1250 hr
= IWineD3DDeviceParent_CreateSurface(This
->device_parent
, parent
, tmpW
, tmpH
, Format
,
1251 Usage
, Pool
, i
, WINED3DCUBEMAP_FACE_POSITIVE_X
, &object
->surfaces
[i
]);
1252 if (hr
!= WINED3D_OK
|| ( (IWineD3DSurfaceImpl
*) object
->surfaces
[i
])->Flags
& SFLAG_OVERSIZE
) {
1253 FIXME("Failed to create surface %p\n", object
);
1255 object
->surfaces
[i
] = NULL
;
1256 IWineD3DTexture_Release((IWineD3DTexture
*)object
);
1262 IWineD3DSurface_SetContainer(object
->surfaces
[i
], (IWineD3DBase
*)object
);
1263 TRACE("Created surface level %d @ %p\n", i
, object
->surfaces
[i
]);
1264 surface_set_texture_target(object
->surfaces
[i
], object
->target
);
1265 /* calculate the next mipmap level */
1266 tmpW
= max(1, tmpW
>> 1);
1267 tmpH
= max(1, tmpH
>> 1);
1269 object
->baseTexture
.internal_preload
= texture_internal_preload
;
1271 TRACE("(%p) : Created texture %p\n", This
, object
);
1275 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice
*iface
,
1276 UINT Width
, UINT Height
, UINT Depth
, UINT Levels
, DWORD Usage
, WINED3DFORMAT Format
,
1277 WINED3DPOOL Pool
, IWineD3DVolumeTexture
**ppVolumeTexture
, IUnknown
*parent
)
1279 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1280 const struct GlPixelFormatDesc
*format_desc
= getFormatDescEntry(Format
, &This
->adapter
->gl_info
);
1281 IWineD3DVolumeTextureImpl
*object
;
1288 /* TODO: It should only be possible to create textures for formats
1289 that are reported as supported */
1290 if (WINED3DFMT_UNKNOWN
>= Format
) {
1291 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
1292 return WINED3DERR_INVALIDCALL
;
1294 if(!GL_SUPPORT(EXT_TEXTURE3D
)) {
1295 WARN("(%p) : Texture cannot be created - no volume texture support\n", This
);
1296 return WINED3DERR_INVALIDCALL
;
1299 /* Calculate levels for mip mapping */
1300 if (Usage
& WINED3DUSAGE_AUTOGENMIPMAP
)
1302 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP
))
1304 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1305 return WINED3DERR_INVALIDCALL
;
1310 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1311 return WINED3DERR_INVALIDCALL
;
1318 Levels
= wined3d_log2i(max(max(Width
, Height
), Depth
)) + 1;
1319 TRACE("Calculated levels = %d\n", Levels
);
1322 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1325 ERR("Out of memory\n");
1326 *ppVolumeTexture
= NULL
;
1327 return WINED3DERR_OUTOFVIDEOMEMORY
;
1330 object
->lpVtbl
= &IWineD3DVolumeTexture_Vtbl
;
1331 hr
= resource_init(&object
->resource
, WINED3DRTYPE_VOLUMETEXTURE
, This
, 0, Usage
, format_desc
, Pool
, parent
);
1334 WARN("Failed to initialize resource, returning %#x\n", hr
);
1335 HeapFree(GetProcessHeap(), 0, object
);
1336 *ppVolumeTexture
= NULL
;
1340 TRACE("(%p) : Created resource %p\n", This
, object
);
1342 IWineD3DDeviceImpl_AddResource(iface
, (IWineD3DResource
*)object
);
1344 basetexture_init(&object
->baseTexture
, Levels
, Usage
);
1346 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
1347 Depth
, Levels
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
1349 /* Is NP2 support for volumes needed? */
1350 object
->baseTexture
.pow2Matrix
[ 0] = 1.0;
1351 object
->baseTexture
.pow2Matrix
[ 5] = 1.0;
1352 object
->baseTexture
.pow2Matrix
[10] = 1.0;
1353 object
->baseTexture
.pow2Matrix
[15] = 1.0;
1355 if (object
->resource
.format_desc
->Flags
& WINED3DFMT_FLAG_FILTERING
)
1357 object
->baseTexture
.minMipLookup
= minMipLookup
;
1358 object
->baseTexture
.magLookup
= magLookup
;
1360 object
->baseTexture
.minMipLookup
= minMipLookup_noFilter
;
1361 object
->baseTexture
.magLookup
= magLookup_noFilter
;
1364 /* Generate all the surfaces */
1369 for (i
= 0; i
< object
->baseTexture
.levels
; i
++)
1372 /* Create the volume */
1373 hr
= IWineD3DDeviceParent_CreateVolume(This
->device_parent
, parent
,
1374 tmpW
, tmpH
, tmpD
, Format
, Pool
, Usage
, &object
->volumes
[i
]);
1376 ERR("Creating a volume for the volume texture failed(%08x)\n", hr
);
1377 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture
*) object
);
1378 *ppVolumeTexture
= NULL
;
1382 /* Set its container to this object */
1383 IWineD3DVolume_SetContainer(object
->volumes
[i
], (IWineD3DBase
*)object
);
1385 /* calculate the next mipmap level */
1386 tmpW
= max(1, tmpW
>> 1);
1387 tmpH
= max(1, tmpH
>> 1);
1388 tmpD
= max(1, tmpD
>> 1);
1390 object
->baseTexture
.internal_preload
= volumetexture_internal_preload
;
1392 *ppVolumeTexture
= (IWineD3DVolumeTexture
*) object
;
1393 TRACE("(%p) : Created volume texture %p\n", This
, object
);
1397 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice
*iface
,
1398 UINT Width
, UINT Height
, UINT Depth
, DWORD Usage
, WINED3DFORMAT Format
,
1399 WINED3DPOOL Pool
, IWineD3DVolume
**ppVolume
, IUnknown
*parent
)
1401 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1402 IWineD3DVolumeImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1403 const struct GlPixelFormatDesc
*format_desc
= getFormatDescEntry(Format
, &GLINFO_LOCATION
);
1406 if(!GL_SUPPORT(EXT_TEXTURE3D
)) {
1407 WARN("(%p) : Volume cannot be created - no volume texture support\n", This
);
1408 return WINED3DERR_INVALIDCALL
;
1411 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1414 ERR("Out of memory\n");
1416 return WINED3DERR_OUTOFVIDEOMEMORY
;
1419 object
->lpVtbl
= &IWineD3DVolume_Vtbl
;
1420 hr
= resource_init(&object
->resource
, WINED3DRTYPE_VOLUME
, This
,
1421 Width
* Height
* Depth
* format_desc
->byte_count
, Usage
, format_desc
, Pool
, parent
);
1424 WARN("Failed to initialize resource, returning %#x\n", hr
);
1425 HeapFree(GetProcessHeap(), 0, object
);
1430 TRACE("(%p) : Created resource %p\n", This
, object
);
1432 IWineD3DDeviceImpl_AddResource(iface
, (IWineD3DResource
*)object
);
1434 *ppVolume
= (IWineD3DVolume
*)object
;
1436 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This
, Width
, Height
,
1437 Depth
, Usage
, Format
, debug_d3dformat(Format
), debug_d3dpool(Pool
));
1439 object
->currentDesc
.Width
= Width
;
1440 object
->currentDesc
.Height
= Height
;
1441 object
->currentDesc
.Depth
= Depth
;
1443 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1444 object
->lockable
= TRUE
;
1445 object
->locked
= FALSE
;
1446 memset(&object
->lockedBox
, 0, sizeof(WINED3DBOX
));
1447 object
->dirty
= TRUE
;
1449 volume_add_dirty_box((IWineD3DVolume
*)object
, NULL
);
1454 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice
*iface
,
1455 UINT EdgeLength
, UINT Levels
, DWORD Usage
, WINED3DFORMAT Format
,
1456 WINED3DPOOL Pool
, IWineD3DCubeTexture
**ppCubeTexture
, IUnknown
*parent
)
1458 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1459 const struct GlPixelFormatDesc
*format_desc
= getFormatDescEntry(Format
, &This
->adapter
->gl_info
);
1460 IWineD3DCubeTextureImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1464 unsigned int pow2EdgeLength
;
1466 /* TODO: It should only be possible to create textures for formats
1467 that are reported as supported */
1468 if (WINED3DFMT_UNKNOWN
>= Format
) {
1469 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This
);
1470 return WINED3DERR_INVALIDCALL
;
1473 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP
) && Pool
!= WINED3DPOOL_SCRATCH
) {
1474 WARN("(%p) : Tried to create not supported cube texture\n", This
);
1475 return WINED3DERR_INVALIDCALL
;
1478 /* Calculate levels for mip mapping */
1479 if (Usage
& WINED3DUSAGE_AUTOGENMIPMAP
)
1481 if (!GL_SUPPORT(SGIS_GENERATE_MIPMAP
))
1483 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1484 return WINED3DERR_INVALIDCALL
;
1489 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1490 return WINED3DERR_INVALIDCALL
;
1497 Levels
= wined3d_log2i(EdgeLength
) + 1;
1498 TRACE("Calculated levels = %d\n", Levels
);
1501 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1504 ERR("Out of memory\n");
1505 *ppCubeTexture
= NULL
;
1506 return WINED3DERR_OUTOFVIDEOMEMORY
;
1509 object
->lpVtbl
= &IWineD3DCubeTexture_Vtbl
;
1510 hr
= resource_init(&object
->resource
, WINED3DRTYPE_CUBETEXTURE
, This
, 0, Usage
, format_desc
, Pool
, parent
);
1513 WARN("Failed to initialize resource, returning %#x\n", hr
);
1514 HeapFree(GetProcessHeap(), 0, object
);
1515 *ppCubeTexture
= NULL
;
1519 TRACE("(%p) : Created resource %p\n", This
, object
);
1521 IWineD3DDeviceImpl_AddResource(iface
, (IWineD3DResource
*)object
);
1523 basetexture_init(&object
->baseTexture
, Levels
, Usage
);
1525 TRACE("(%p) Create Cube Texture\n", This
);
1527 /* Find the nearest pow2 match */
1529 while (pow2EdgeLength
< EdgeLength
) pow2EdgeLength
<<= 1;
1531 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO
) || (EdgeLength
== pow2EdgeLength
)) {
1532 /* Precalculated scaling for 'faked' non power of two texture coords */
1533 object
->baseTexture
.pow2Matrix
[ 0] = 1.0;
1534 object
->baseTexture
.pow2Matrix
[ 5] = 1.0;
1535 object
->baseTexture
.pow2Matrix
[10] = 1.0;
1536 object
->baseTexture
.pow2Matrix
[15] = 1.0;
1538 /* Precalculated scaling for 'faked' non power of two texture coords */
1539 object
->baseTexture
.pow2Matrix
[ 0] = ((float)EdgeLength
) / ((float)pow2EdgeLength
);
1540 object
->baseTexture
.pow2Matrix
[ 5] = ((float)EdgeLength
) / ((float)pow2EdgeLength
);
1541 object
->baseTexture
.pow2Matrix
[10] = ((float)EdgeLength
) / ((float)pow2EdgeLength
);
1542 object
->baseTexture
.pow2Matrix
[15] = 1.0;
1543 object
->baseTexture
.pow2Matrix_identity
= FALSE
;
1546 if (object
->resource
.format_desc
->Flags
& WINED3DFMT_FLAG_FILTERING
)
1548 object
->baseTexture
.minMipLookup
= minMipLookup
;
1549 object
->baseTexture
.magLookup
= magLookup
;
1551 object
->baseTexture
.minMipLookup
= minMipLookup_noFilter
;
1552 object
->baseTexture
.magLookup
= magLookup_noFilter
;
1555 /* Generate all the surfaces */
1557 for (i
= 0; i
< object
->baseTexture
.levels
; i
++) {
1559 /* Create the 6 faces */
1560 for (j
= 0; j
< 6; j
++) {
1561 static const GLenum cube_targets
[6] = {
1562 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB
,
1563 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB
,
1564 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB
,
1565 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB
,
1566 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB
,
1567 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
1570 hr
= IWineD3DDeviceParent_CreateSurface(This
->device_parent
, parent
, tmpW
, tmpW
,
1571 Format
, Usage
, Pool
, i
/* Level */, j
, &object
->surfaces
[j
][i
]);
1574 FIXME("(%p) Failed to create surface\n",object
);
1575 IWineD3DCubeTexture_Release((IWineD3DCubeTexture
*)object
);
1576 *ppCubeTexture
= NULL
;
1579 IWineD3DSurface_SetContainer(object
->surfaces
[j
][i
], (IWineD3DBase
*)object
);
1580 TRACE("Created surface level %d @ %p,\n", i
, object
->surfaces
[j
][i
]);
1581 surface_set_texture_target(object
->surfaces
[j
][i
], cube_targets
[j
]);
1583 tmpW
= max(1, tmpW
>> 1);
1585 object
->baseTexture
.internal_preload
= cubetexture_internal_preload
;
1587 TRACE("(%p) : Created Cube Texture %p\n", This
, object
);
1588 *ppCubeTexture
= (IWineD3DCubeTexture
*) object
;
1592 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice
*iface
, WINED3DQUERYTYPE Type
, IWineD3DQuery
**ppQuery
, IUnknown
* parent
) {
1593 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1594 IWineD3DQueryImpl
*object
; /*NOTE: impl ref allowed since this is a create function */
1595 HRESULT hr
= WINED3DERR_NOTAVAILABLE
;
1596 const IWineD3DQueryVtbl
*vtable
;
1598 /* Just a check to see if we support this type of query */
1600 case WINED3DQUERYTYPE_OCCLUSION
:
1601 TRACE("(%p) occlusion query\n", This
);
1602 if (GL_SUPPORT(ARB_OCCLUSION_QUERY
))
1605 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1607 vtable
= &IWineD3DOcclusionQuery_Vtbl
;
1610 case WINED3DQUERYTYPE_EVENT
:
1611 if(!(GL_SUPPORT(NV_FENCE
) || GL_SUPPORT(APPLE_FENCE
) )) {
1612 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1613 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1615 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This
);
1617 vtable
= &IWineD3DEventQuery_Vtbl
;
1621 case WINED3DQUERYTYPE_VCACHE
:
1622 case WINED3DQUERYTYPE_RESOURCEMANAGER
:
1623 case WINED3DQUERYTYPE_VERTEXSTATS
:
1624 case WINED3DQUERYTYPE_TIMESTAMP
:
1625 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT
:
1626 case WINED3DQUERYTYPE_TIMESTAMPFREQ
:
1627 case WINED3DQUERYTYPE_PIPELINETIMINGS
:
1628 case WINED3DQUERYTYPE_INTERFACETIMINGS
:
1629 case WINED3DQUERYTYPE_VERTEXTIMINGS
:
1630 case WINED3DQUERYTYPE_PIXELTIMINGS
:
1631 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS
:
1632 case WINED3DQUERYTYPE_CACHEUTILIZATION
:
1634 /* Use the base Query vtable until we have a special one for each query */
1635 vtable
= &IWineD3DQuery_Vtbl
;
1636 FIXME("(%p) Unhandled query type %d\n", This
, Type
);
1638 if(NULL
== ppQuery
|| hr
!= WINED3D_OK
) {
1642 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1645 ERR("Out of memory\n");
1647 return WINED3DERR_OUTOFVIDEOMEMORY
;
1650 object
->lpVtbl
= vtable
;
1651 object
->type
= Type
;
1652 object
->state
= QUERY_CREATED
;
1653 object
->wineD3DDevice
= This
;
1654 object
->parent
= parent
;
1657 *ppQuery
= (IWineD3DQuery
*)object
;
1659 /* allocated the 'extended' data based on the type of query requested */
1661 case WINED3DQUERYTYPE_OCCLUSION
:
1662 object
->extendedData
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WineQueryOcclusionData
));
1663 ((WineQueryOcclusionData
*)(object
->extendedData
))->ctx
= This
->activeContext
;
1665 if(GL_SUPPORT(ARB_OCCLUSION_QUERY
)) {
1666 TRACE("(%p) Allocating data for an occlusion query\n", This
);
1668 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
1670 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData
*)(object
->extendedData
))->queryId
));
1674 case WINED3DQUERYTYPE_EVENT
:
1675 object
->extendedData
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WineQueryEventData
));
1676 ((WineQueryEventData
*)(object
->extendedData
))->ctx
= This
->activeContext
;
1678 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
1680 if(GL_SUPPORT(APPLE_FENCE
)) {
1681 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData
*)(object
->extendedData
))->fenceId
));
1682 checkGLcall("glGenFencesAPPLE");
1683 } else if(GL_SUPPORT(NV_FENCE
)) {
1684 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData
*)(object
->extendedData
))->fenceId
));
1685 checkGLcall("glGenFencesNV");
1690 case WINED3DQUERYTYPE_VCACHE
:
1691 case WINED3DQUERYTYPE_RESOURCEMANAGER
:
1692 case WINED3DQUERYTYPE_VERTEXSTATS
:
1693 case WINED3DQUERYTYPE_TIMESTAMP
:
1694 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT
:
1695 case WINED3DQUERYTYPE_TIMESTAMPFREQ
:
1696 case WINED3DQUERYTYPE_PIPELINETIMINGS
:
1697 case WINED3DQUERYTYPE_INTERFACETIMINGS
:
1698 case WINED3DQUERYTYPE_VERTEXTIMINGS
:
1699 case WINED3DQUERYTYPE_PIXELTIMINGS
:
1700 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS
:
1701 case WINED3DQUERYTYPE_CACHEUTILIZATION
:
1703 object
->extendedData
= 0;
1704 FIXME("(%p) Unhandled query type %d\n",This
, Type
);
1706 TRACE("(%p) : Created Query %p\n", This
, object
);
1710 /*****************************************************************************
1711 * IWineD3DDeviceImpl_SetupFullscreenWindow
1713 * Helper function that modifies a HWND's Style and ExStyle for proper
1717 * iface: Pointer to the IWineD3DDevice interface
1718 * window: Window to setup
1720 *****************************************************************************/
1721 static LONG
fullscreen_style(LONG orig_style
) {
1722 LONG style
= orig_style
;
1723 style
&= ~WS_CAPTION
;
1724 style
&= ~WS_THICKFRAME
;
1726 /* Make sure the window is managed, otherwise we won't get keyboard input */
1727 style
|= WS_POPUP
| WS_SYSMENU
;
1732 static LONG
fullscreen_exStyle(LONG orig_exStyle
) {
1733 LONG exStyle
= orig_exStyle
;
1735 /* Filter out window decorations */
1736 exStyle
&= ~WS_EX_WINDOWEDGE
;
1737 exStyle
&= ~WS_EX_CLIENTEDGE
;
1742 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice
*iface
, HWND window
, UINT w
, UINT h
) {
1743 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1745 LONG style
, exStyle
;
1746 /* Don't do anything if an original style is stored.
1747 * That shouldn't happen
1749 TRACE("(%p): Setting up window %p for exclusive mode\n", This
, window
);
1750 if (This
->style
|| This
->exStyle
) {
1751 ERR("(%p): Want to change the window parameters of HWND %p, but "
1752 "another style is stored for restoration afterwards\n", This
, window
);
1755 /* Get the parameters and save them */
1756 style
= GetWindowLongW(window
, GWL_STYLE
);
1757 exStyle
= GetWindowLongW(window
, GWL_EXSTYLE
);
1758 This
->style
= style
;
1759 This
->exStyle
= exStyle
;
1761 style
= fullscreen_style(style
);
1762 exStyle
= fullscreen_exStyle(exStyle
);
1764 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1765 This
->style
, This
->exStyle
, style
, exStyle
);
1767 SetWindowLongW(window
, GWL_STYLE
, style
);
1768 SetWindowLongW(window
, GWL_EXSTYLE
, exStyle
);
1770 /* Inform the window about the update. */
1771 SetWindowPos(window
, HWND_TOP
, 0, 0,
1772 w
, h
, SWP_FRAMECHANGED
| SWP_SHOWWINDOW
);
1775 /*****************************************************************************
1776 * IWineD3DDeviceImpl_RestoreWindow
1778 * Helper function that restores a windows' properties when taking it out
1779 * of fullscreen mode
1782 * iface: Pointer to the IWineD3DDevice interface
1783 * window: Window to setup
1785 *****************************************************************************/
1786 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice
*iface
, HWND window
) {
1787 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1788 LONG style
, exStyle
;
1790 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1791 * switch, do nothing
1793 if (!This
->style
&& !This
->exStyle
) return;
1795 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1796 This
, window
, This
->style
, This
->exStyle
);
1798 style
= GetWindowLongW(window
, GWL_STYLE
);
1799 exStyle
= GetWindowLongW(window
, GWL_EXSTYLE
);
1801 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1802 * Some applications change it before calling Reset() when switching between windowed and
1803 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1805 if(style
== fullscreen_style(This
->style
) &&
1806 exStyle
== fullscreen_style(This
->exStyle
)) {
1807 SetWindowLongW(window
, GWL_STYLE
, This
->style
);
1808 SetWindowLongW(window
, GWL_EXSTYLE
, This
->exStyle
);
1811 /* Delete the old values */
1815 /* Inform the window about the update */
1816 SetWindowPos(window
, 0 /* InsertAfter, ignored */,
1817 0, 0, 0, 0, /* Pos, Size, ignored */
1818 SWP_FRAMECHANGED
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
);
1821 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1822 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice
*iface
,
1823 WINED3DPRESENT_PARAMETERS
*pPresentationParameters
, IWineD3DSwapChain
**ppSwapChain
,
1824 IUnknown
*parent
, WINED3DSURFTYPE surface_type
)
1826 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
1829 IWineD3DSwapChainImpl
*object
; /** NOTE: impl ref allowed since this is a create function **/
1831 IUnknown
*bufferParent
;
1832 BOOL displaymode_set
= FALSE
;
1833 WINED3DDISPLAYMODE Mode
;
1834 const struct GlPixelFormatDesc
*format_desc
;
1836 TRACE("(%p) : Created Additional Swap Chain\n", This
);
1838 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1839 * does a device hold a reference to a swap chain giving them a lifetime of the device
1840 * or does the swap chain notify the device of its destruction.
1841 *******************************/
1843 /* Check the params */
1844 if(pPresentationParameters
->BackBufferCount
> WINED3DPRESENT_BACK_BUFFER_MAX
) {
1845 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters
->BackBufferCount
);
1846 return WINED3DERR_INVALIDCALL
;
1847 } else if (pPresentationParameters
->BackBufferCount
> 1) {
1848 FIXME("The app requests more than one back buffer, this can't be supported properly. Please configure the application to use double buffering(=1 back buffer) if possible\n");
1851 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
1854 ERR("Out of memory\n");
1855 *ppSwapChain
= NULL
;
1856 return WINED3DERR_OUTOFVIDEOMEMORY
;
1859 switch(surface_type
) {
1861 object
->lpVtbl
= &IWineGDISwapChain_Vtbl
;
1863 case SURFACE_OPENGL
:
1864 object
->lpVtbl
= &IWineD3DSwapChain_Vtbl
;
1866 case SURFACE_UNKNOWN
:
1867 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1868 HeapFree(GetProcessHeap(), 0, object
);
1869 return WINED3DERR_INVALIDCALL
;
1871 object
->wineD3DDevice
= This
;
1872 object
->parent
= parent
;
1875 *ppSwapChain
= (IWineD3DSwapChain
*)object
;
1877 /*********************
1878 * Lookup the window Handle and the relating X window handle
1879 ********************/
1881 /* Setup hwnd we are using, plus which display this equates to */
1882 object
->win_handle
= pPresentationParameters
->hDeviceWindow
;
1883 if (!object
->win_handle
) {
1884 object
->win_handle
= This
->createParms
.hFocusWindow
;
1886 if(!pPresentationParameters
->Windowed
&& object
->win_handle
) {
1887 IWineD3DDeviceImpl_SetupFullscreenWindow(iface
, object
->win_handle
,
1888 pPresentationParameters
->BackBufferWidth
,
1889 pPresentationParameters
->BackBufferHeight
);
1892 hDc
= GetDC(object
->win_handle
);
1893 TRACE("Using hDc %p\n", hDc
);
1896 WARN("Failed to get a HDc for Window %p\n", object
->win_handle
);
1897 return WINED3DERR_NOTAVAILABLE
;
1900 /* Get info on the current display setup */
1901 IWineD3D_GetAdapterDisplayMode(This
->wineD3D
, This
->adapter
->num
, &Mode
);
1902 object
->orig_width
= Mode
.Width
;
1903 object
->orig_height
= Mode
.Height
;
1904 object
->orig_fmt
= Mode
.Format
;
1905 format_desc
= getFormatDescEntry(Mode
.Format
, &GLINFO_LOCATION
);
1907 if (pPresentationParameters
->Windowed
&&
1908 ((pPresentationParameters
->BackBufferWidth
== 0) ||
1909 (pPresentationParameters
->BackBufferHeight
== 0) ||
1910 (pPresentationParameters
->BackBufferFormat
== WINED3DFMT_UNKNOWN
))) {
1913 GetClientRect(object
->win_handle
, &Rect
);
1915 if (pPresentationParameters
->BackBufferWidth
== 0) {
1916 pPresentationParameters
->BackBufferWidth
= Rect
.right
;
1917 TRACE("Updating width to %d\n", pPresentationParameters
->BackBufferWidth
);
1919 if (pPresentationParameters
->BackBufferHeight
== 0) {
1920 pPresentationParameters
->BackBufferHeight
= Rect
.bottom
;
1921 TRACE("Updating height to %d\n", pPresentationParameters
->BackBufferHeight
);
1923 if (pPresentationParameters
->BackBufferFormat
== WINED3DFMT_UNKNOWN
) {
1924 pPresentationParameters
->BackBufferFormat
= object
->orig_fmt
;
1925 TRACE("Updating format to %s\n", debug_d3dformat(object
->orig_fmt
));
1929 /* Put the correct figures in the presentation parameters */
1930 TRACE("Copying across presentation parameters\n");
1931 object
->presentParms
= *pPresentationParameters
;
1933 TRACE("calling rendertarget CB\n");
1934 hr
= IWineD3DDeviceParent_CreateRenderTarget(This
->device_parent
, parent
,
1935 object
->presentParms
.BackBufferWidth
, object
->presentParms
.BackBufferHeight
,
1936 object
->presentParms
.BackBufferFormat
, object
->presentParms
.MultiSampleType
,
1937 object
->presentParms
.MultiSampleQuality
, TRUE
/* Lockable */, &object
->frontBuffer
);
1938 if (SUCCEEDED(hr
)) {
1939 IWineD3DSurface_SetContainer(object
->frontBuffer
, (IWineD3DBase
*)object
);
1940 ((IWineD3DSurfaceImpl
*)object
->frontBuffer
)->Flags
|= SFLAG_SWAPCHAIN
;
1941 if(surface_type
== SURFACE_OPENGL
) {
1942 IWineD3DSurface_ModifyLocation(object
->frontBuffer
, SFLAG_INDRAWABLE
, TRUE
);
1945 ERR("Failed to create the front buffer\n");
1949 /*********************
1950 * Windowed / Fullscreen
1951 *******************/
1954 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1955 * so we should really check to see if there is a fullscreen swapchain already
1956 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1957 **************************************/
1959 if (!pPresentationParameters
->Windowed
) {
1960 WINED3DDISPLAYMODE mode
;
1963 /* Change the display settings */
1964 mode
.Width
= pPresentationParameters
->BackBufferWidth
;
1965 mode
.Height
= pPresentationParameters
->BackBufferHeight
;
1966 mode
.Format
= pPresentationParameters
->BackBufferFormat
;
1967 mode
.RefreshRate
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
1969 IWineD3DDevice_SetDisplayMode(iface
, 0, &mode
);
1970 displaymode_set
= TRUE
;
1974 * Create an opengl context for the display visual
1975 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1976 * use different properties after that point in time. FIXME: How to handle when requested format
1977 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1978 * it chooses is identical to the one already being used!
1979 **********************************/
1980 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1982 object
->context
= HeapAlloc(GetProcessHeap(), 0, sizeof(object
->context
));
1983 if(!object
->context
) {
1984 ERR("Failed to create the context array\n");
1988 object
->num_contexts
= 1;
1990 if(surface_type
== SURFACE_OPENGL
) {
1991 object
->context
[0] = CreateContext(This
, (IWineD3DSurfaceImpl
*) object
->frontBuffer
, object
->win_handle
, FALSE
/* pbuffer */, pPresentationParameters
);
1992 if (!object
->context
[0]) {
1993 ERR("Failed to create a new context\n");
1994 hr
= WINED3DERR_NOTAVAILABLE
;
1997 TRACE("Context created (HWND=%p, glContext=%p)\n",
1998 object
->win_handle
, object
->context
[0]->glCtx
);
2002 /*********************
2003 * Create the back, front and stencil buffers
2004 *******************/
2005 if(object
->presentParms
.BackBufferCount
> 0) {
2008 object
->backBuffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface
*) * object
->presentParms
.BackBufferCount
);
2009 if(!object
->backBuffer
) {
2010 ERR("Out of memory\n");
2015 for(i
= 0; i
< object
->presentParms
.BackBufferCount
; i
++) {
2016 TRACE("calling rendertarget CB\n");
2017 hr
= IWineD3DDeviceParent_CreateRenderTarget(This
->device_parent
, parent
,
2018 object
->presentParms
.BackBufferWidth
, object
->presentParms
.BackBufferHeight
,
2019 object
->presentParms
.BackBufferFormat
, object
->presentParms
.MultiSampleType
,
2020 object
->presentParms
.MultiSampleQuality
, TRUE
/* Lockable */, &object
->backBuffer
[i
]);
2022 IWineD3DSurface_SetContainer(object
->backBuffer
[i
], (IWineD3DBase
*)object
);
2023 ((IWineD3DSurfaceImpl
*)object
->backBuffer
[i
])->Flags
|= SFLAG_SWAPCHAIN
;
2025 ERR("Cannot create new back buffer\n");
2028 if(surface_type
== SURFACE_OPENGL
) {
2030 glDrawBuffer(GL_BACK
);
2031 checkGLcall("glDrawBuffer(GL_BACK)");
2036 object
->backBuffer
= NULL
;
2038 /* Single buffering - draw to front buffer */
2039 if(surface_type
== SURFACE_OPENGL
) {
2041 glDrawBuffer(GL_FRONT
);
2042 checkGLcall("glDrawBuffer(GL_FRONT)");
2047 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
2048 if (pPresentationParameters
->EnableAutoDepthStencil
&& surface_type
== SURFACE_OPENGL
) {
2049 TRACE("Creating depth stencil buffer\n");
2050 if (This
->auto_depth_stencil_buffer
== NULL
) {
2051 hr
= IWineD3DDeviceParent_CreateDepthStencilSurface(This
->device_parent
, parent
,
2052 object
->presentParms
.BackBufferWidth
, object
->presentParms
.BackBufferHeight
,
2053 object
->presentParms
.AutoDepthStencilFormat
, object
->presentParms
.MultiSampleType
,
2054 object
->presentParms
.MultiSampleQuality
, FALSE
/* FIXME: Discard */,
2055 &This
->auto_depth_stencil_buffer
);
2056 if (SUCCEEDED(hr
)) {
2057 IWineD3DSurface_SetContainer(This
->auto_depth_stencil_buffer
, 0);
2059 ERR("Failed to create the auto depth stencil\n");
2065 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain
*) object
, &object
->orig_gamma
);
2067 TRACE("Created swapchain %p\n", object
);
2068 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object
->frontBuffer
, object
->backBuffer
? object
->backBuffer
[0] : NULL
, pPresentationParameters
->EnableAutoDepthStencil
);
2072 if (displaymode_set
) {
2076 SetRect(&clip_rc
, 0, 0, object
->orig_width
, object
->orig_height
);
2079 /* Change the display settings */
2080 memset(&devmode
, 0, sizeof(devmode
));
2081 devmode
.dmSize
= sizeof(devmode
);
2082 devmode
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
2083 devmode
.dmBitsPerPel
= format_desc
->byte_count
* 8;
2084 devmode
.dmPelsWidth
= object
->orig_width
;
2085 devmode
.dmPelsHeight
= object
->orig_height
;
2086 ChangeDisplaySettingsExW(This
->adapter
->DeviceName
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
);
2089 if (object
->backBuffer
) {
2091 for(i
= 0; i
< object
->presentParms
.BackBufferCount
; i
++) {
2092 if(object
->backBuffer
[i
]) {
2093 IWineD3DSurface_GetParent(object
->backBuffer
[i
], &bufferParent
);
2094 IUnknown_Release(bufferParent
); /* once for the get parent */
2095 if (IUnknown_Release(bufferParent
) > 0) {
2096 FIXME("(%p) Something's still holding the back buffer\n",This
);
2100 HeapFree(GetProcessHeap(), 0, object
->backBuffer
);
2101 object
->backBuffer
= NULL
;
2103 if(object
->context
&& object
->context
[0])
2104 DestroyContext(This
, object
->context
[0]);
2105 if(object
->frontBuffer
) {
2106 IWineD3DSurface_GetParent(object
->frontBuffer
, &bufferParent
);
2107 IUnknown_Release(bufferParent
); /* once for the get parent */
2108 if (IUnknown_Release(bufferParent
) > 0) {
2109 FIXME("(%p) Something's still holding the front buffer\n",This
);
2112 HeapFree(GetProcessHeap(), 0, object
);
2116 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
2117 static UINT WINAPI
IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice
*iface
) {
2118 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2119 TRACE("(%p)\n", This
);
2121 return This
->NumberOfSwapChains
;
2124 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice
*iface
, UINT iSwapChain
, IWineD3DSwapChain
**pSwapChain
) {
2125 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2126 TRACE("(%p) : swapchain %d\n", This
, iSwapChain
);
2128 if(iSwapChain
< This
->NumberOfSwapChains
) {
2129 *pSwapChain
= This
->swapchains
[iSwapChain
];
2130 IWineD3DSwapChain_AddRef(*pSwapChain
);
2131 TRACE("(%p) returning %p\n", This
, *pSwapChain
);
2134 TRACE("Swapchain out of range\n");
2136 return WINED3DERR_INVALIDCALL
;
2141 * Vertex Declaration
2143 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppVertexDeclaration
,
2144 IUnknown
*parent
, const WINED3DVERTEXELEMENT
*elements
, UINT element_count
) {
2145 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2146 IWineD3DVertexDeclarationImpl
*object
= NULL
;
2147 HRESULT hr
= WINED3D_OK
;
2149 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
2150 This
, ((IWineD3DImpl
*)This
->wineD3D
)->dxVersion
, elements
, element_count
, ppVertexDeclaration
);
2152 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
2155 ERR("Out of memory\n");
2156 *ppVertexDeclaration
= NULL
;
2157 return WINED3DERR_OUTOFVIDEOMEMORY
;
2160 object
->lpVtbl
= &IWineD3DVertexDeclaration_Vtbl
;
2161 object
->wineD3DDevice
= This
;
2162 object
->parent
= parent
;
2165 *ppVertexDeclaration
= (IWineD3DVertexDeclaration
*)object
;
2167 hr
= vertexdeclaration_init(object
, elements
, element_count
);
2170 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration
*)object
);
2171 *ppVertexDeclaration
= NULL
;
2177 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl
*This
, /* For the GL info, which has the type table */
2178 DWORD fvf
, WINED3DVERTEXELEMENT
** ppVertexElements
) {
2180 unsigned int idx
, idx2
;
2181 unsigned int offset
;
2182 BOOL has_pos
= (fvf
& WINED3DFVF_POSITION_MASK
) != 0;
2183 BOOL has_blend
= (fvf
& WINED3DFVF_XYZB5
) > WINED3DFVF_XYZRHW
;
2184 BOOL has_blend_idx
= has_blend
&&
2185 (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB5
) ||
2186 (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
) ||
2187 (fvf
& WINED3DFVF_LASTBETA_UBYTE4
));
2188 BOOL has_normal
= (fvf
& WINED3DFVF_NORMAL
) != 0;
2189 BOOL has_psize
= (fvf
& WINED3DFVF_PSIZE
) != 0;
2190 BOOL has_diffuse
= (fvf
& WINED3DFVF_DIFFUSE
) != 0;
2191 BOOL has_specular
= (fvf
& WINED3DFVF_SPECULAR
) !=0;
2193 DWORD num_textures
= (fvf
& WINED3DFVF_TEXCOUNT_MASK
) >> WINED3DFVF_TEXCOUNT_SHIFT
;
2194 DWORD texcoords
= (fvf
& 0xFFFF0000) >> 16;
2195 WINED3DVERTEXELEMENT
*elements
= NULL
;
2198 DWORD num_blends
= 1 + (((fvf
& WINED3DFVF_XYZB5
) - WINED3DFVF_XYZB1
) >> 1);
2199 if (has_blend_idx
) num_blends
--;
2201 /* Compute declaration size */
2202 size
= has_pos
+ (has_blend
&& num_blends
> 0) + has_blend_idx
+ has_normal
+
2203 has_psize
+ has_diffuse
+ has_specular
+ num_textures
;
2205 /* convert the declaration */
2206 elements
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(WINED3DVERTEXELEMENT
));
2207 if (!elements
) return ~0U;
2211 if (!has_blend
&& (fvf
& WINED3DFVF_XYZRHW
)) {
2212 elements
[idx
].format
= WINED3DFMT_R32G32B32A32_FLOAT
;
2213 elements
[idx
].usage
= WINED3DDECLUSAGE_POSITIONT
;
2215 else if ((fvf
& WINED3DFVF_XYZW
) == WINED3DFVF_XYZW
) {
2216 elements
[idx
].format
= WINED3DFMT_R32G32B32A32_FLOAT
;
2217 elements
[idx
].usage
= WINED3DDECLUSAGE_POSITION
;
2220 elements
[idx
].format
= WINED3DFMT_R32G32B32_FLOAT
;
2221 elements
[idx
].usage
= WINED3DDECLUSAGE_POSITION
;
2223 elements
[idx
].usage_idx
= 0;
2226 if (has_blend
&& (num_blends
> 0)) {
2227 if (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB2
) && (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
))
2228 elements
[idx
].format
= WINED3DFMT_A8R8G8B8
;
2230 switch(num_blends
) {
2231 case 1: elements
[idx
].format
= WINED3DFMT_R32_FLOAT
; break;
2232 case 2: elements
[idx
].format
= WINED3DFMT_R32G32_FLOAT
; break;
2233 case 3: elements
[idx
].format
= WINED3DFMT_R32G32B32_FLOAT
; break;
2234 case 4: elements
[idx
].format
= WINED3DFMT_R32G32B32A32_FLOAT
; break;
2236 ERR("Unexpected amount of blend values: %u\n", num_blends
);
2239 elements
[idx
].usage
= WINED3DDECLUSAGE_BLENDWEIGHT
;
2240 elements
[idx
].usage_idx
= 0;
2243 if (has_blend_idx
) {
2244 if (fvf
& WINED3DFVF_LASTBETA_UBYTE4
||
2245 (((fvf
& WINED3DFVF_XYZB5
) == WINED3DFVF_XYZB2
) && (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
)))
2246 elements
[idx
].format
= WINED3DFMT_R8G8B8A8_UINT
;
2247 else if (fvf
& WINED3DFVF_LASTBETA_D3DCOLOR
)
2248 elements
[idx
].format
= WINED3DFMT_A8R8G8B8
;
2250 elements
[idx
].format
= WINED3DFMT_R32_FLOAT
;
2251 elements
[idx
].usage
= WINED3DDECLUSAGE_BLENDINDICES
;
2252 elements
[idx
].usage_idx
= 0;
2256 elements
[idx
].format
= WINED3DFMT_R32G32B32_FLOAT
;
2257 elements
[idx
].usage
= WINED3DDECLUSAGE_NORMAL
;
2258 elements
[idx
].usage_idx
= 0;
2262 elements
[idx
].format
= WINED3DFMT_R32_FLOAT
;
2263 elements
[idx
].usage
= WINED3DDECLUSAGE_PSIZE
;
2264 elements
[idx
].usage_idx
= 0;
2268 elements
[idx
].format
= WINED3DFMT_A8R8G8B8
;
2269 elements
[idx
].usage
= WINED3DDECLUSAGE_COLOR
;
2270 elements
[idx
].usage_idx
= 0;
2274 elements
[idx
].format
= WINED3DFMT_A8R8G8B8
;
2275 elements
[idx
].usage
= WINED3DDECLUSAGE_COLOR
;
2276 elements
[idx
].usage_idx
= 1;
2279 for (idx2
= 0; idx2
< num_textures
; idx2
++) {
2280 unsigned int numcoords
= (texcoords
>> (idx2
*2)) & 0x03;
2281 switch (numcoords
) {
2282 case WINED3DFVF_TEXTUREFORMAT1
:
2283 elements
[idx
].format
= WINED3DFMT_R32_FLOAT
;
2285 case WINED3DFVF_TEXTUREFORMAT2
:
2286 elements
[idx
].format
= WINED3DFMT_R32G32_FLOAT
;
2288 case WINED3DFVF_TEXTUREFORMAT3
:
2289 elements
[idx
].format
= WINED3DFMT_R32G32B32_FLOAT
;
2291 case WINED3DFVF_TEXTUREFORMAT4
:
2292 elements
[idx
].format
= WINED3DFMT_R32G32B32A32_FLOAT
;
2295 elements
[idx
].usage
= WINED3DDECLUSAGE_TEXCOORD
;
2296 elements
[idx
].usage_idx
= idx2
;
2300 /* Now compute offsets, and initialize the rest of the fields */
2301 for (idx
= 0, offset
= 0; idx
< size
; ++idx
)
2303 const struct GlPixelFormatDesc
*format_desc
= getFormatDescEntry(elements
[idx
].format
, &This
->adapter
->gl_info
);
2304 elements
[idx
].input_slot
= 0;
2305 elements
[idx
].method
= WINED3DDECLMETHOD_DEFAULT
;
2306 elements
[idx
].offset
= offset
;
2307 offset
+= format_desc
->component_count
* format_desc
->component_size
;
2310 *ppVertexElements
= elements
;
2314 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppVertexDeclaration
, IUnknown
*Parent
, DWORD Fvf
) {
2315 WINED3DVERTEXELEMENT
* elements
= NULL
;
2316 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2320 size
= ConvertFvfToDeclaration(This
, Fvf
, &elements
);
2321 if (size
== ~0U) return WINED3DERR_OUTOFVIDEOMEMORY
;
2323 hr
= IWineD3DDevice_CreateVertexDeclaration(iface
, ppVertexDeclaration
, Parent
, elements
, size
);
2324 HeapFree(GetProcessHeap(), 0, elements
);
2325 if (hr
!= S_OK
) return hr
;
2330 static HRESULT WINAPI
IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexDeclaration
*vertex_declaration
, CONST DWORD
*pFunction
, IWineD3DVertexShader
**ppVertexShader
, IUnknown
*parent
) {
2331 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2332 IWineD3DVertexShaderImpl
*object
; /* NOTE: impl usage is ok, this is a create */
2333 HRESULT hr
= WINED3D_OK
;
2335 if (!pFunction
) return WINED3DERR_INVALIDCALL
;
2337 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
2340 ERR("Out of memory\n");
2341 *ppVertexShader
= NULL
;
2342 return WINED3DERR_OUTOFVIDEOMEMORY
;
2345 object
->lpVtbl
= &IWineD3DVertexShader_Vtbl
;
2346 object
->parent
= parent
;
2347 shader_init(&object
->baseShader
, iface
, IWineD3DVertexShaderImpl_shader_ins
);
2348 list_add_head(&This
->shaders
, &object
->baseShader
.shader_list_entry
);
2349 *ppVertexShader
= (IWineD3DVertexShader
*)object
;
2351 TRACE("(%p) : Created vertex shader %p\n", This
, *ppVertexShader
);
2353 if (vertex_declaration
) {
2354 IWineD3DVertexShader_FakeSemantics(*ppVertexShader
, vertex_declaration
);
2357 hr
= IWineD3DVertexShader_SetFunction(*ppVertexShader
, pFunction
);
2360 WARN("(%p) : Failed to set function, returning %#x\n", iface
, hr
);
2361 IWineD3DVertexShader_Release(*ppVertexShader
);
2362 *ppVertexShader
= NULL
;
2369 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice
*iface
, CONST DWORD
*pFunction
, IWineD3DPixelShader
**ppPixelShader
, IUnknown
*parent
) {
2370 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2371 IWineD3DPixelShaderImpl
*object
; /* NOTE: impl allowed, this is a create */
2372 HRESULT hr
= WINED3D_OK
;
2374 if (!pFunction
) return WINED3DERR_INVALIDCALL
;
2376 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
2379 ERR("Out of memory\n");
2380 *ppPixelShader
= NULL
;
2381 return WINED3DERR_OUTOFVIDEOMEMORY
;
2384 object
->lpVtbl
= &IWineD3DPixelShader_Vtbl
;
2385 object
->parent
= parent
;
2386 shader_init(&object
->baseShader
, iface
, IWineD3DPixelShaderImpl_shader_ins
);
2387 list_add_head(&This
->shaders
, &object
->baseShader
.shader_list_entry
);
2388 *ppPixelShader
= (IWineD3DPixelShader
*)object
;
2390 TRACE("(%p) : Created pixel shader %p\n", This
, *ppPixelShader
);
2392 hr
= IWineD3DPixelShader_SetFunction(*ppPixelShader
, pFunction
);
2395 WARN("(%p) : Failed to set function, returning %#x\n", iface
, hr
);
2396 IWineD3DPixelShader_Release(*ppPixelShader
);
2397 *ppPixelShader
= NULL
;
2404 static HRESULT WINAPI
IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice
*iface
, DWORD Flags
,
2405 const PALETTEENTRY
*PalEnt
, IWineD3DPalette
**Palette
, IUnknown
*Parent
)
2407 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2408 IWineD3DPaletteImpl
*object
;
2410 TRACE("(%p)->(%x, %p, %p, %p)\n", This
, Flags
, PalEnt
, Palette
, Parent
);
2412 /* Create the new object */
2413 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DPaletteImpl
));
2415 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
2416 return E_OUTOFMEMORY
;
2419 object
->lpVtbl
= &IWineD3DPalette_Vtbl
;
2421 object
->Flags
= Flags
;
2422 object
->parent
= Parent
;
2423 object
->wineD3DDevice
= This
;
2424 object
->palNumEntries
= IWineD3DPaletteImpl_Size(Flags
);
2425 object
->hpal
= CreatePalette((const LOGPALETTE
*)&(object
->palVersion
));
2428 HeapFree( GetProcessHeap(), 0, object
);
2429 return E_OUTOFMEMORY
;
2432 hr
= IWineD3DPalette_SetEntries((IWineD3DPalette
*) object
, 0, 0, IWineD3DPaletteImpl_Size(Flags
), PalEnt
);
2434 IWineD3DPalette_Release((IWineD3DPalette
*) object
);
2438 *Palette
= (IWineD3DPalette
*) object
;
2443 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl
*This
, const char *filename
) {
2447 HDC dcb
= NULL
, dcs
= NULL
;
2448 WINEDDCOLORKEY colorkey
;
2450 hbm
= LoadImageA(NULL
, filename
, IMAGE_BITMAP
, 0, 0, LR_LOADFROMFILE
| LR_CREATEDIBSECTION
);
2453 GetObjectA(hbm
, sizeof(BITMAP
), &bm
);
2454 dcb
= CreateCompatibleDC(NULL
);
2456 SelectObject(dcb
, hbm
);
2460 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
2461 * couldn't be loaded
2463 memset(&bm
, 0, sizeof(bm
));
2468 hr
= IWineD3DDevice_CreateSurface((IWineD3DDevice
*) This
, bm
.bmWidth
, bm
.bmHeight
, WINED3DFMT_R5G6B5
,
2469 TRUE
, FALSE
, 0, &This
->logo_surface
, WINED3DRTYPE_SURFACE
, 0,
2470 WINED3DPOOL_DEFAULT
, WINED3DMULTISAMPLE_NONE
, 0, SURFACE_OPENGL
, NULL
);
2472 ERR("Wine logo requested, but failed to create surface\n");
2477 hr
= IWineD3DSurface_GetDC(This
->logo_surface
, &dcs
);
2478 if(FAILED(hr
)) goto out
;
2479 BitBlt(dcs
, 0, 0, bm
.bmWidth
, bm
.bmHeight
, dcb
, 0, 0, SRCCOPY
);
2480 IWineD3DSurface_ReleaseDC(This
->logo_surface
, dcs
);
2482 colorkey
.dwColorSpaceLowValue
= 0;
2483 colorkey
.dwColorSpaceHighValue
= 0;
2484 IWineD3DSurface_SetColorKey(This
->logo_surface
, WINEDDCKEY_SRCBLT
, &colorkey
);
2486 /* Fill the surface with a white color to show that wined3d is there */
2487 IWineD3DDevice_ColorFill((IWineD3DDevice
*) This
, This
->logo_surface
, NULL
, 0xffffffff);
2500 static void create_dummy_textures(IWineD3DDeviceImpl
*This
) {
2502 /* Under DirectX you can have texture stage operations even if no texture is
2503 bound, whereas opengl will only do texture operations when a valid texture is
2504 bound. We emulate this by creating dummy textures and binding them to each
2505 texture stage, but disable all stages by default. Hence if a stage is enabled
2506 then the default texture will kick in until replaced by a SetTexture call */
2509 if(GL_SUPPORT(APPLE_CLIENT_STORAGE
)) {
2510 /* The dummy texture does not have client storage backing */
2511 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
2512 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2514 for (i
= 0; i
< GL_LIMITS(textures
); i
++) {
2515 GLubyte white
= 255;
2517 /* Make appropriate texture active */
2518 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
+ i
));
2519 checkGLcall("glActiveTextureARB");
2521 /* Generate an opengl texture name */
2522 glGenTextures(1, &This
->dummyTextureName
[i
]);
2523 checkGLcall("glGenTextures");
2524 TRACE("Dummy Texture %d given name %d\n", i
, This
->dummyTextureName
[i
]);
2526 /* Generate a dummy 2d texture (not using 1d because they cause many
2527 * DRI drivers fall back to sw) */
2528 glBindTexture(GL_TEXTURE_2D
, This
->dummyTextureName
[i
]);
2529 checkGLcall("glBindTexture");
2531 glTexImage2D(GL_TEXTURE_2D
, 0, GL_LUMINANCE
, 1, 1, 0, GL_LUMINANCE
, GL_UNSIGNED_BYTE
, &white
);
2532 checkGLcall("glTexImage2D");
2534 if(GL_SUPPORT(APPLE_CLIENT_STORAGE
)) {
2535 /* Reenable because if supported it is enabled by default */
2536 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
2537 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2543 static HRESULT WINAPI
IWineD3DDeviceImpl_Init3D(IWineD3DDevice
*iface
,
2544 WINED3DPRESENT_PARAMETERS
*pPresentationParameters
)
2546 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2547 IWineD3DSwapChainImpl
*swapchain
= NULL
;
2552 TRACE("(%p)->(%p)\n", This
, pPresentationParameters
);
2554 if(This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
2555 if(!This
->adapter
->opengl
) return WINED3DERR_INVALIDCALL
;
2557 /* TODO: Test if OpenGL is compiled in and loaded */
2559 TRACE("(%p) : Creating stateblock\n", This
);
2560 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2561 hr
= IWineD3DDevice_CreateStateBlock(iface
,
2563 (IWineD3DStateBlock
**)&This
->stateBlock
,
2565 if (WINED3D_OK
!= hr
) { /* Note: No parent needed for initial internal stateblock */
2566 WARN("Failed to create stateblock\n");
2569 TRACE("(%p) : Created stateblock (%p)\n", This
, This
->stateBlock
);
2570 This
->updateStateBlock
= This
->stateBlock
;
2571 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
2573 This
->render_targets
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DSurface
*) * GL_LIMITS(buffers
));
2574 This
->draw_buffers
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(GLenum
) * GL_LIMITS(buffers
));
2576 This
->NumberOfPalettes
= 1;
2577 This
->palettes
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(PALETTEENTRY
*));
2578 if(!This
->palettes
|| !This
->render_targets
|| !This
->draw_buffers
) {
2579 ERR("Out of memory!\n");
2582 This
->palettes
[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY
) * 256);
2583 if(!This
->palettes
[0]) {
2584 ERR("Out of memory!\n");
2587 for (i
= 0; i
< 256; ++i
) {
2588 This
->palettes
[0][i
].peRed
= 0xFF;
2589 This
->palettes
[0][i
].peGreen
= 0xFF;
2590 This
->palettes
[0][i
].peBlue
= 0xFF;
2591 This
->palettes
[0][i
].peFlags
= 0xFF;
2593 This
->currentPalette
= 0;
2595 /* Initialize the texture unit mapping to a 1:1 mapping */
2596 for (state
= 0; state
< MAX_COMBINED_SAMPLERS
; ++state
) {
2597 if (state
< GL_LIMITS(fragment_samplers
)) {
2598 This
->texUnitMap
[state
] = state
;
2599 This
->rev_tex_unit_map
[state
] = state
;
2601 This
->texUnitMap
[state
] = -1;
2602 This
->rev_tex_unit_map
[state
] = -1;
2606 /* Setup the implicit swapchain */
2607 TRACE("Creating implicit swapchain\n");
2608 hr
= IWineD3DDeviceParent_CreateSwapChain(This
->device_parent
,
2609 pPresentationParameters
, (IWineD3DSwapChain
**)&swapchain
);
2612 WARN("Failed to create implicit swapchain\n");
2616 This
->NumberOfSwapChains
= 1;
2617 This
->swapchains
= HeapAlloc(GetProcessHeap(), 0, This
->NumberOfSwapChains
* sizeof(IWineD3DSwapChain
*));
2618 if(!This
->swapchains
) {
2619 ERR("Out of memory!\n");
2622 This
->swapchains
[0] = (IWineD3DSwapChain
*) swapchain
;
2624 if(swapchain
->backBuffer
&& swapchain
->backBuffer
[0]) {
2625 TRACE("Setting rendertarget to %p\n", swapchain
->backBuffer
);
2626 This
->render_targets
[0] = swapchain
->backBuffer
[0];
2627 This
->lastActiveRenderTarget
= swapchain
->backBuffer
[0];
2630 TRACE("Setting rendertarget to %p\n", swapchain
->frontBuffer
);
2631 This
->render_targets
[0] = swapchain
->frontBuffer
;
2632 This
->lastActiveRenderTarget
= swapchain
->frontBuffer
;
2634 IWineD3DSurface_AddRef(This
->render_targets
[0]);
2635 This
->activeContext
= swapchain
->context
[0];
2636 This
->lastThread
= GetCurrentThreadId();
2638 /* Depth Stencil support */
2639 This
->stencilBufferTarget
= This
->auto_depth_stencil_buffer
;
2640 if (NULL
!= This
->stencilBufferTarget
) {
2641 IWineD3DSurface_AddRef(This
->stencilBufferTarget
);
2644 hr
= This
->shader_backend
->shader_alloc_private(iface
);
2646 TRACE("Shader private data couldn't be allocated\n");
2649 hr
= This
->frag_pipe
->alloc_private(iface
);
2651 TRACE("Fragment pipeline private data couldn't be allocated\n");
2654 hr
= This
->blitter
->alloc_private(iface
);
2656 TRACE("Blitter private data couldn't be allocated\n");
2660 /* Set up some starting GL setup */
2662 /* Setup all the devices defaults */
2663 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock
*)This
->stateBlock
);
2664 create_dummy_textures(This
);
2668 /* Initialize the current view state */
2669 This
->view_ident
= 1;
2670 This
->contexts
[0]->last_was_rhw
= 0;
2671 glGetIntegerv(GL_MAX_LIGHTS
, &This
->maxConcurrentLights
);
2672 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2674 switch(wined3d_settings
.offscreen_rendering_mode
) {
2677 This
->offscreenBuffer
= GL_BACK
;
2680 case ORM_BACKBUFFER
:
2682 if(This
->activeContext
->aux_buffers
> 0) {
2683 TRACE("Using auxilliary buffer for offscreen rendering\n");
2684 This
->offscreenBuffer
= GL_AUX0
;
2686 TRACE("Using back buffer for offscreen rendering\n");
2687 This
->offscreenBuffer
= GL_BACK
;
2692 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This
, This
);
2695 /* Clear the screen */
2696 IWineD3DDevice_Clear((IWineD3DDevice
*) This
, 0, NULL
,
2697 WINED3DCLEAR_TARGET
| pPresentationParameters
->EnableAutoDepthStencil
? WINED3DCLEAR_ZBUFFER
| WINED3DCLEAR_STENCIL
: 0,
2700 This
->d3d_initialized
= TRUE
;
2702 if(wined3d_settings
.logo
) {
2703 IWineD3DDeviceImpl_LoadLogo(This
, wined3d_settings
.logo
);
2705 This
->highest_dirty_ps_const
= 0;
2706 This
->highest_dirty_vs_const
= 0;
2710 HeapFree(GetProcessHeap(), 0, This
->render_targets
);
2711 HeapFree(GetProcessHeap(), 0, This
->draw_buffers
);
2712 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
2713 This
->NumberOfSwapChains
= 0;
2714 if(This
->palettes
) {
2715 HeapFree(GetProcessHeap(), 0, This
->palettes
[0]);
2716 HeapFree(GetProcessHeap(), 0, This
->palettes
);
2718 This
->NumberOfPalettes
= 0;
2720 IWineD3DSwapChain_Release( (IWineD3DSwapChain
*) swapchain
);
2722 if(This
->stateBlock
) {
2723 IWineD3DStateBlock_Release((IWineD3DStateBlock
*) This
->stateBlock
);
2724 This
->stateBlock
= NULL
;
2726 if (This
->blit_priv
) {
2727 This
->blitter
->free_private(iface
);
2729 if (This
->fragment_priv
) {
2730 This
->frag_pipe
->free_private(iface
);
2732 if (This
->shader_priv
) {
2733 This
->shader_backend
->shader_free_private(iface
);
2738 static HRESULT WINAPI
IWineD3DDeviceImpl_InitGDI(IWineD3DDevice
*iface
,
2739 WINED3DPRESENT_PARAMETERS
*pPresentationParameters
)
2741 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2742 IWineD3DSwapChainImpl
*swapchain
= NULL
;
2745 /* Setup the implicit swapchain */
2746 TRACE("Creating implicit swapchain\n");
2747 hr
= IWineD3DDeviceParent_CreateSwapChain(This
->device_parent
,
2748 pPresentationParameters
, (IWineD3DSwapChain
**)&swapchain
);
2751 WARN("Failed to create implicit swapchain\n");
2755 This
->NumberOfSwapChains
= 1;
2756 This
->swapchains
= HeapAlloc(GetProcessHeap(), 0, This
->NumberOfSwapChains
* sizeof(IWineD3DSwapChain
*));
2757 if(!This
->swapchains
) {
2758 ERR("Out of memory!\n");
2761 This
->swapchains
[0] = (IWineD3DSwapChain
*) swapchain
;
2765 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
2769 static HRESULT WINAPI
device_unload_resource(IWineD3DResource
*resource
, void *ctx
)
2771 IWineD3DResource_UnLoad(resource
);
2772 IWineD3DResource_Release(resource
);
2776 static HRESULT WINAPI
IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice
*iface
, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface
, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain
) {
2777 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2780 TRACE("(%p)\n", This
);
2782 if(!This
->d3d_initialized
) return WINED3DERR_INVALIDCALL
;
2784 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2785 * it was created. Thus make sure a context is active for the glDelete* calls
2787 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
2789 if(This
->logo_surface
) IWineD3DSurface_Release(This
->logo_surface
);
2791 /* Unload resources */
2792 IWineD3DDevice_EnumResources(iface
, device_unload_resource
, NULL
);
2794 TRACE("Deleting high order patches\n");
2795 for(i
= 0; i
< PATCHMAP_SIZE
; i
++) {
2796 struct list
*e1
, *e2
;
2797 struct WineD3DRectPatch
*patch
;
2798 LIST_FOR_EACH_SAFE(e1
, e2
, &This
->patches
[i
]) {
2799 patch
= LIST_ENTRY(e1
, struct WineD3DRectPatch
, entry
);
2800 IWineD3DDevice_DeletePatch(iface
, patch
->Handle
);
2804 /* Delete the palette conversion shader if it is around */
2805 if(This
->paletteConversionShader
) {
2807 GL_EXTCALL(glDeleteProgramsARB(1, &This
->paletteConversionShader
));
2809 This
->paletteConversionShader
= 0;
2812 /* Delete the pbuffer context if there is any */
2813 if(This
->pbufferContext
) DestroyContext(This
, This
->pbufferContext
);
2815 /* Delete the mouse cursor texture */
2816 if(This
->cursorTexture
) {
2818 glDeleteTextures(1, &This
->cursorTexture
);
2820 This
->cursorTexture
= 0;
2823 for (sampler
= 0; sampler
< MAX_FRAGMENT_SAMPLERS
; ++sampler
) {
2824 IWineD3DDevice_SetTexture(iface
, sampler
, NULL
);
2826 for (sampler
= 0; sampler
< MAX_VERTEX_SAMPLERS
; ++sampler
) {
2827 IWineD3DDevice_SetTexture(iface
, WINED3DVERTEXTEXTURESAMPLER0
+ sampler
, NULL
);
2830 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2831 * private data, it might contain opengl pointers
2833 if(This
->depth_blt_texture
) {
2834 glDeleteTextures(1, &This
->depth_blt_texture
);
2835 This
->depth_blt_texture
= 0;
2837 if (This
->depth_blt_rb
) {
2838 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This
->depth_blt_rb
));
2839 This
->depth_blt_rb
= 0;
2840 This
->depth_blt_rb_w
= 0;
2841 This
->depth_blt_rb_h
= 0;
2844 /* Release the update stateblock */
2845 if(IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
) > 0){
2846 if(This
->updateStateBlock
!= This
->stateBlock
)
2847 FIXME("(%p) Something's still holding the Update stateblock\n",This
);
2849 This
->updateStateBlock
= NULL
;
2851 { /* because were not doing proper internal refcounts releasing the primary state block
2852 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2853 to set this->stateBlock = NULL; first */
2854 IWineD3DStateBlock
*stateBlock
= (IWineD3DStateBlock
*)This
->stateBlock
;
2855 This
->stateBlock
= NULL
;
2857 /* Release the stateblock */
2858 if(IWineD3DStateBlock_Release(stateBlock
) > 0){
2859 FIXME("(%p) Something's still holding the Update stateblock\n",This
);
2863 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2864 This
->blitter
->free_private(iface
);
2865 This
->frag_pipe
->free_private(iface
);
2866 This
->shader_backend
->shader_free_private(iface
);
2868 /* Release the buffers (with sanity checks)*/
2869 TRACE("Releasing the depth stencil buffer at %p\n", This
->stencilBufferTarget
);
2870 if(This
->stencilBufferTarget
!= NULL
&& (IWineD3DSurface_Release(This
->stencilBufferTarget
) >0)){
2871 if(This
->auto_depth_stencil_buffer
!= This
->stencilBufferTarget
)
2872 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This
);
2874 This
->stencilBufferTarget
= NULL
;
2876 TRACE("Releasing the render target at %p\n", This
->render_targets
[0]);
2877 if(IWineD3DSurface_Release(This
->render_targets
[0]) >0){
2878 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2880 TRACE("Setting rendertarget to NULL\n");
2881 This
->render_targets
[0] = NULL
;
2883 if (This
->auto_depth_stencil_buffer
) {
2884 if(D3DCB_DestroyDepthStencilSurface(This
->auto_depth_stencil_buffer
) > 0) {
2885 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This
);
2887 This
->auto_depth_stencil_buffer
= NULL
;
2890 for(i
=0; i
< This
->NumberOfSwapChains
; i
++) {
2891 TRACE("Releasing the implicit swapchain %d\n", i
);
2892 if (D3DCB_DestroySwapChain(This
->swapchains
[i
]) > 0) {
2893 FIXME("(%p) Something's still holding the implicit swapchain\n", This
);
2897 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
2898 This
->swapchains
= NULL
;
2899 This
->NumberOfSwapChains
= 0;
2901 for (i
= 0; i
< This
->NumberOfPalettes
; i
++) HeapFree(GetProcessHeap(), 0, This
->palettes
[i
]);
2902 HeapFree(GetProcessHeap(), 0, This
->palettes
);
2903 This
->palettes
= NULL
;
2904 This
->NumberOfPalettes
= 0;
2906 HeapFree(GetProcessHeap(), 0, This
->render_targets
);
2907 HeapFree(GetProcessHeap(), 0, This
->draw_buffers
);
2908 This
->render_targets
= NULL
;
2909 This
->draw_buffers
= NULL
;
2911 This
->d3d_initialized
= FALSE
;
2915 static HRESULT WINAPI
IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice
*iface
, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain
) {
2916 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2919 for(i
=0; i
< This
->NumberOfSwapChains
; i
++) {
2920 TRACE("Releasing the implicit swapchain %d\n", i
);
2921 if (D3DCB_DestroySwapChain(This
->swapchains
[i
]) > 0) {
2922 FIXME("(%p) Something's still holding the implicit swapchain\n", This
);
2926 HeapFree(GetProcessHeap(), 0, This
->swapchains
);
2927 This
->swapchains
= NULL
;
2928 This
->NumberOfSwapChains
= 0;
2932 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2933 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2934 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2936 * There is no way to deactivate thread safety once it is enabled.
2938 static void WINAPI
IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice
*iface
) {
2939 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
2941 /*For now just store the flag(needed in case of ddraw) */
2942 This
->createParms
.BehaviorFlags
|= WINED3DCREATE_MULTITHREADED
;
2947 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
,
2948 const WINED3DDISPLAYMODE
* pMode
) {
2950 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
2952 const struct GlPixelFormatDesc
*format_desc
= getFormatDescEntry(pMode
->Format
, &GLINFO_LOCATION
);
2955 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This
, iSwapChain
, pMode
, pMode
->Width
, pMode
->Height
, pMode
->RefreshRate
, debug_d3dformat(pMode
->Format
));
2957 /* Resize the screen even without a window:
2958 * The app could have unset it with SetCooperativeLevel, but not called
2959 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2960 * but we don't have any hwnd
2963 memset(&devmode
, 0, sizeof(devmode
));
2964 devmode
.dmSize
= sizeof(devmode
);
2965 devmode
.dmFields
= DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
;
2966 devmode
.dmBitsPerPel
= format_desc
->byte_count
* 8;
2967 devmode
.dmPelsWidth
= pMode
->Width
;
2968 devmode
.dmPelsHeight
= pMode
->Height
;
2970 devmode
.dmDisplayFrequency
= pMode
->RefreshRate
;
2971 if (pMode
->RefreshRate
!= 0) {
2972 devmode
.dmFields
|= DM_DISPLAYFREQUENCY
;
2975 /* Only change the mode if necessary */
2976 if( (This
->ddraw_width
== pMode
->Width
) &&
2977 (This
->ddraw_height
== pMode
->Height
) &&
2978 (This
->ddraw_format
== pMode
->Format
) &&
2979 (pMode
->RefreshRate
== 0) ) {
2983 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
);
2984 if (ret
!= DISP_CHANGE_SUCCESSFUL
) {
2985 if(devmode
.dmDisplayFrequency
!= 0) {
2986 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2987 devmode
.dmFields
&= ~DM_DISPLAYFREQUENCY
;
2988 devmode
.dmDisplayFrequency
= 0;
2989 ret
= ChangeDisplaySettingsExW(NULL
, &devmode
, NULL
, CDS_FULLSCREEN
, NULL
) != DISP_CHANGE_SUCCESSFUL
;
2991 if(ret
!= DISP_CHANGE_SUCCESSFUL
) {
2992 return WINED3DERR_NOTAVAILABLE
;
2996 /* Store the new values */
2997 This
->ddraw_width
= pMode
->Width
;
2998 This
->ddraw_height
= pMode
->Height
;
2999 This
->ddraw_format
= pMode
->Format
;
3001 /* And finally clip mouse to our screen */
3002 SetRect(&clip_rc
, 0, 0, pMode
->Width
, pMode
->Height
);
3003 ClipCursor(&clip_rc
);
3008 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice
*iface
, IWineD3D
**ppD3D
) {
3009 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3010 *ppD3D
= This
->wineD3D
;
3011 TRACE("(%p) : wineD3D returning %p\n", This
, *ppD3D
);
3012 IWineD3D_AddRef(*ppD3D
);
3016 static UINT WINAPI
IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice
*iface
) {
3017 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3019 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This
,
3020 (This
->adapter
->TextureRam
/(1024*1024)),
3021 ((This
->adapter
->TextureRam
- This
->adapter
->UsedTextureRam
) / (1024*1024)));
3022 /* return simulated texture memory left */
3023 return (This
->adapter
->TextureRam
- This
->adapter
->UsedTextureRam
);
3027 * Get / Set Stream Source
3029 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice
*iface
, UINT StreamNumber
,
3030 IWineD3DBuffer
*pStreamData
, UINT OffsetInBytes
, UINT Stride
)
3032 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3033 IWineD3DBuffer
*oldSrc
;
3035 if (StreamNumber
>= MAX_STREAMS
) {
3036 WARN("Stream out of range %d\n", StreamNumber
);
3037 return WINED3DERR_INVALIDCALL
;
3038 } else if(OffsetInBytes
& 0x3) {
3039 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes
);
3040 return WINED3DERR_INVALIDCALL
;
3043 oldSrc
= This
->updateStateBlock
->streamSource
[StreamNumber
];
3044 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This
, StreamNumber
, oldSrc
, pStreamData
, OffsetInBytes
, Stride
);
3046 This
->updateStateBlock
->changed
.streamSource
|= 1 << StreamNumber
;
3048 if(oldSrc
== pStreamData
&&
3049 This
->updateStateBlock
->streamStride
[StreamNumber
] == Stride
&&
3050 This
->updateStateBlock
->streamOffset
[StreamNumber
] == OffsetInBytes
) {
3051 TRACE("Application is setting the old values over, nothing to do\n");
3055 This
->updateStateBlock
->streamSource
[StreamNumber
] = pStreamData
;
3057 This
->updateStateBlock
->streamStride
[StreamNumber
] = Stride
;
3058 This
->updateStateBlock
->streamOffset
[StreamNumber
] = OffsetInBytes
;
3061 /* Handle recording of state blocks */
3062 if (This
->isRecordingState
) {
3063 TRACE("Recording... not performing anything\n");
3064 if (pStreamData
) IWineD3DBuffer_AddRef(pStreamData
);
3065 if (oldSrc
) IWineD3DBuffer_Release(oldSrc
);
3069 if (pStreamData
!= NULL
) {
3070 InterlockedIncrement(&((struct wined3d_buffer
*)pStreamData
)->bind_count
);
3071 IWineD3DBuffer_AddRef(pStreamData
);
3073 if (oldSrc
!= NULL
) {
3074 InterlockedDecrement(&((struct wined3d_buffer
*)oldSrc
)->bind_count
);
3075 IWineD3DBuffer_Release(oldSrc
);
3078 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
3083 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice
*iface
,
3084 UINT StreamNumber
, IWineD3DBuffer
**pStream
, UINT
*pOffset
, UINT
*pStride
)
3086 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3088 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This
, StreamNumber
,
3089 This
->stateBlock
->streamSource
[StreamNumber
],
3090 This
->stateBlock
->streamOffset
[StreamNumber
],
3091 This
->stateBlock
->streamStride
[StreamNumber
]);
3093 if (StreamNumber
>= MAX_STREAMS
) {
3094 WARN("Stream out of range %d\n", StreamNumber
);
3095 return WINED3DERR_INVALIDCALL
;
3097 *pStream
= This
->stateBlock
->streamSource
[StreamNumber
];
3098 *pStride
= This
->stateBlock
->streamStride
[StreamNumber
];
3100 *pOffset
= This
->stateBlock
->streamOffset
[StreamNumber
];
3103 if (*pStream
!= NULL
) {
3104 IWineD3DBuffer_AddRef(*pStream
); /* We have created a new reference to the VB */
3109 static HRESULT WINAPI
IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT Divider
) {
3110 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3111 UINT oldFlags
= This
->updateStateBlock
->streamFlags
[StreamNumber
];
3112 UINT oldFreq
= This
->updateStateBlock
->streamFreq
[StreamNumber
];
3114 /* Verify input at least in d3d9 this is invalid*/
3115 if( (Divider
& WINED3DSTREAMSOURCE_INSTANCEDATA
) && (Divider
& WINED3DSTREAMSOURCE_INDEXEDDATA
)){
3116 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
3117 return WINED3DERR_INVALIDCALL
;
3119 if( (Divider
& WINED3DSTREAMSOURCE_INSTANCEDATA
) && StreamNumber
== 0 ){
3120 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
3121 return WINED3DERR_INVALIDCALL
;
3124 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
3125 return WINED3DERR_INVALIDCALL
;
3128 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This
, StreamNumber
, Divider
);
3129 This
->updateStateBlock
->streamFlags
[StreamNumber
] = Divider
& (WINED3DSTREAMSOURCE_INSTANCEDATA
| WINED3DSTREAMSOURCE_INDEXEDDATA
);
3131 This
->updateStateBlock
->changed
.streamFreq
|= 1 << StreamNumber
;
3132 This
->updateStateBlock
->streamFreq
[StreamNumber
] = Divider
& 0x7FFFFF;
3134 if(This
->updateStateBlock
->streamFreq
[StreamNumber
] != oldFreq
||
3135 This
->updateStateBlock
->streamFlags
[StreamNumber
] != oldFlags
) {
3136 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
3142 static HRESULT WINAPI
IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice
*iface
, UINT StreamNumber
, UINT
* Divider
) {
3143 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3145 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This
, StreamNumber
, Divider
);
3146 *Divider
= This
->updateStateBlock
->streamFreq
[StreamNumber
] | This
->updateStateBlock
->streamFlags
[StreamNumber
];
3148 TRACE("(%p) : returning %d\n", This
, *Divider
);
3154 * Get / Set & Multiply Transform
3156 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE d3dts
, CONST WINED3DMATRIX
* lpmatrix
) {
3157 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3159 /* Most of this routine, comments included copied from ddraw tree initially: */
3160 TRACE("(%p) : Transform State=%s\n", This
, debug_d3dtstype(d3dts
));
3162 /* Handle recording of state blocks */
3163 if (This
->isRecordingState
) {
3164 TRACE("Recording... not performing anything\n");
3165 This
->updateStateBlock
->changed
.transform
[d3dts
>> 5] |= 1 << (d3dts
& 0x1f);
3166 This
->updateStateBlock
->transforms
[d3dts
] = *lpmatrix
;
3171 * If the new matrix is the same as the current one,
3172 * we cut off any further processing. this seems to be a reasonable
3173 * optimization because as was noticed, some apps (warcraft3 for example)
3174 * tend towards setting the same matrix repeatedly for some reason.
3176 * From here on we assume that the new matrix is different, wherever it matters.
3178 if (!memcmp(&This
->stateBlock
->transforms
[d3dts
].u
.m
[0][0], lpmatrix
, sizeof(WINED3DMATRIX
))) {
3179 TRACE("The app is setting the same matrix over again\n");
3182 conv_mat(lpmatrix
, &This
->stateBlock
->transforms
[d3dts
].u
.m
[0][0]);
3186 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
3187 where ViewMat = Camera space, WorldMat = world space.
3189 In OpenGL, camera and world space is combined into GL_MODELVIEW
3190 matrix. The Projection matrix stay projection matrix.
3193 /* Capture the times we can just ignore the change for now */
3194 if (d3dts
== WINED3DTS_VIEW
) { /* handle the VIEW matrix */
3195 This
->view_ident
= !memcmp(lpmatrix
, identity
, 16 * sizeof(float));
3196 /* Handled by the state manager */
3199 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TRANSFORM(d3dts
));
3203 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, WINED3DMATRIX
* pMatrix
) {
3204 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3205 TRACE("(%p) : for Transform State %s\n", This
, debug_d3dtstype(State
));
3206 *pMatrix
= This
->stateBlock
->transforms
[State
];
3210 static HRESULT WINAPI
IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice
*iface
, WINED3DTRANSFORMSTATETYPE State
, CONST WINED3DMATRIX
* pMatrix
) {
3211 const WINED3DMATRIX
*mat
= NULL
;
3214 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
3215 * below means it will be recorded in a state block change, but it
3216 * works regardless where it is recorded.
3217 * If this is found to be wrong, change to StateBlock.
3219 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3220 TRACE("(%p) : For state %s\n", This
, debug_d3dtstype(State
));
3222 if (State
<= HIGHEST_TRANSFORMSTATE
)
3224 mat
= &This
->updateStateBlock
->transforms
[State
];
3226 FIXME("Unhandled transform state!!\n");
3229 multiply_matrix(&temp
, mat
, pMatrix
);
3231 /* Apply change via set transform - will reapply to eg. lights this way */
3232 return IWineD3DDeviceImpl_SetTransform(iface
, State
, &temp
);
3238 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
3239 you can reference any indexes you want as long as that number max are enabled at any
3240 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
3241 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
3242 but when recording, just build a chain pretty much of commands to be replayed. */
3244 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLight(IWineD3DDevice
*iface
, DWORD Index
, CONST WINED3DLIGHT
* pLight
) {
3246 PLIGHTINFOEL
*object
= NULL
;
3247 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
3250 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3251 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This
, Index
, pLight
, Hi
);
3253 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
3257 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
3258 return WINED3DERR_INVALIDCALL
;
3261 switch(pLight
->Type
) {
3262 case WINED3DLIGHT_POINT
:
3263 case WINED3DLIGHT_SPOT
:
3264 case WINED3DLIGHT_PARALLELPOINT
:
3265 case WINED3DLIGHT_GLSPOT
:
3266 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
3269 if(pLight
->Attenuation0
< 0.0 || pLight
->Attenuation1
< 0.0 || pLight
->Attenuation2
< 0.0) {
3270 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
3271 return WINED3DERR_INVALIDCALL
;
3275 case WINED3DLIGHT_DIRECTIONAL
:
3276 /* Ignores attenuation */
3280 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
3281 return WINED3DERR_INVALIDCALL
;
3284 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
3285 object
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
3286 if(object
->OriginalIndex
== Index
) break;
3291 TRACE("Adding new light\n");
3292 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
3294 ERR("Out of memory error when allocating a light\n");
3295 return E_OUTOFMEMORY
;
3297 list_add_head(&This
->updateStateBlock
->lightMap
[Hi
], &object
->entry
);
3298 object
->glIndex
= -1;
3299 object
->OriginalIndex
= Index
;
3300 object
->changed
= TRUE
;
3303 /* Initialize the object */
3304 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
,
3305 pLight
->Diffuse
.r
, pLight
->Diffuse
.g
, pLight
->Diffuse
.b
, pLight
->Diffuse
.a
,
3306 pLight
->Specular
.r
, pLight
->Specular
.g
, pLight
->Specular
.b
, pLight
->Specular
.a
,
3307 pLight
->Ambient
.r
, pLight
->Ambient
.g
, pLight
->Ambient
.b
, pLight
->Ambient
.a
);
3308 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight
->Position
.x
, pLight
->Position
.y
, pLight
->Position
.z
,
3309 pLight
->Direction
.x
, pLight
->Direction
.y
, pLight
->Direction
.z
);
3310 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight
->Range
, pLight
->Falloff
, pLight
->Theta
, pLight
->Phi
);
3312 /* Save away the information */
3313 object
->OriginalParms
= *pLight
;
3315 switch (pLight
->Type
) {
3316 case WINED3DLIGHT_POINT
:
3318 object
->lightPosn
[0] = pLight
->Position
.x
;
3319 object
->lightPosn
[1] = pLight
->Position
.y
;
3320 object
->lightPosn
[2] = pLight
->Position
.z
;
3321 object
->lightPosn
[3] = 1.0f
;
3322 object
->cutoff
= 180.0f
;
3326 case WINED3DLIGHT_DIRECTIONAL
:
3328 object
->lightPosn
[0] = -pLight
->Direction
.x
;
3329 object
->lightPosn
[1] = -pLight
->Direction
.y
;
3330 object
->lightPosn
[2] = -pLight
->Direction
.z
;
3331 object
->lightPosn
[3] = 0.0;
3332 object
->exponent
= 0.0f
;
3333 object
->cutoff
= 180.0f
;
3336 case WINED3DLIGHT_SPOT
:
3338 object
->lightPosn
[0] = pLight
->Position
.x
;
3339 object
->lightPosn
[1] = pLight
->Position
.y
;
3340 object
->lightPosn
[2] = pLight
->Position
.z
;
3341 object
->lightPosn
[3] = 1.0;
3344 object
->lightDirn
[0] = pLight
->Direction
.x
;
3345 object
->lightDirn
[1] = pLight
->Direction
.y
;
3346 object
->lightDirn
[2] = pLight
->Direction
.z
;
3347 object
->lightDirn
[3] = 1.0;
3350 * opengl-ish and d3d-ish spot lights use too different models for the
3351 * light "intensity" as a function of the angle towards the main light direction,
3352 * so we only can approximate very roughly.
3353 * however spot lights are rather rarely used in games (if ever used at all).
3354 * furthermore if still used, probably nobody pays attention to such details.
3356 if (pLight
->Falloff
== 0) {
3357 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
3358 * falloff resp. exponent parameter as an exponent, so the spot light lighting
3359 * will always be 1.0 for both of them, and we don't have to care for the
3360 * rest of the rather complex calculation
3362 object
->exponent
= 0;
3364 rho
= pLight
->Theta
+ (pLight
->Phi
- pLight
->Theta
)/(2*pLight
->Falloff
);
3365 if (rho
< 0.0001) rho
= 0.0001f
;
3366 object
->exponent
= -0.3/log(cos(rho
/2));
3368 if (object
->exponent
> 128.0) {
3369 object
->exponent
= 128.0;
3371 object
->cutoff
= pLight
->Phi
*90/M_PI
;
3377 FIXME("Unrecognized light type %d\n", pLight
->Type
);
3380 /* Update the live definitions if the light is currently assigned a glIndex */
3381 if (object
->glIndex
!= -1 && !This
->isRecordingState
) {
3382 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(object
->glIndex
));
3387 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLight(IWineD3DDevice
*iface
, DWORD Index
, WINED3DLIGHT
* pLight
) {
3388 PLIGHTINFOEL
*lightInfo
= NULL
;
3389 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3390 DWORD Hi
= LIGHTMAP_HASHFUNC(Index
);
3392 TRACE("(%p) : Idx(%d), pLight(%p)\n", This
, Index
, pLight
);
3394 LIST_FOR_EACH(e
, &This
->stateBlock
->lightMap
[Hi
]) {
3395 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
3396 if(lightInfo
->OriginalIndex
== Index
) break;
3400 if (lightInfo
== NULL
) {
3401 TRACE("Light information requested but light not defined\n");
3402 return WINED3DERR_INVALIDCALL
;
3405 *pLight
= lightInfo
->OriginalParms
;
3410 * Get / Set Light Enable
3411 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
3413 static HRESULT WINAPI
IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice
*iface
, DWORD Index
, BOOL Enable
) {
3414 PLIGHTINFOEL
*lightInfo
= NULL
;
3415 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3416 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
3418 TRACE("(%p) : Idx(%d), enable? %d\n", This
, Index
, Enable
);
3420 /* Tests show true = 128...not clear why */
3421 Enable
= Enable
? 128: 0;
3423 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
3424 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
3425 if(lightInfo
->OriginalIndex
== Index
) break;
3428 TRACE("Found light: %p\n", lightInfo
);
3430 /* Special case - enabling an undefined light creates one with a strict set of parms! */
3431 if (lightInfo
== NULL
) {
3433 TRACE("Light enabled requested but light not defined, so defining one!\n");
3434 IWineD3DDeviceImpl_SetLight(iface
, Index
, &WINED3D_default_light
);
3436 /* Search for it again! Should be fairly quick as near head of list */
3437 LIST_FOR_EACH(e
, &This
->updateStateBlock
->lightMap
[Hi
]) {
3438 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
3439 if(lightInfo
->OriginalIndex
== Index
) break;
3442 if (lightInfo
== NULL
) {
3443 FIXME("Adding default lights has failed dismally\n");
3444 return WINED3DERR_INVALIDCALL
;
3448 lightInfo
->enabledChanged
= TRUE
;
3450 if(lightInfo
->glIndex
!= -1) {
3451 if(!This
->isRecordingState
) {
3452 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(lightInfo
->glIndex
));
3455 This
->updateStateBlock
->activeLights
[lightInfo
->glIndex
] = NULL
;
3456 lightInfo
->glIndex
= -1;
3458 TRACE("Light already disabled, nothing to do\n");
3460 lightInfo
->enabled
= FALSE
;
3462 lightInfo
->enabled
= TRUE
;
3463 if (lightInfo
->glIndex
!= -1) {
3465 TRACE("Nothing to do as light was enabled\n");
3468 /* Find a free gl light */
3469 for(i
= 0; i
< This
->maxConcurrentLights
; i
++) {
3470 if(This
->updateStateBlock
->activeLights
[i
] == NULL
) {
3471 This
->updateStateBlock
->activeLights
[i
] = lightInfo
;
3472 lightInfo
->glIndex
= i
;
3476 if(lightInfo
->glIndex
== -1) {
3477 /* Our tests show that Windows returns D3D_OK in this situation, even with
3478 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3479 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3480 * as well for those lights.
3482 * TODO: Test how this affects rendering
3484 WARN("Too many concurrently active lights\n");
3488 /* i == lightInfo->glIndex */
3489 if(!This
->isRecordingState
) {
3490 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_ACTIVELIGHT(i
));
3498 static HRESULT WINAPI
IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice
*iface
, DWORD Index
,BOOL
* pEnable
) {
3500 PLIGHTINFOEL
*lightInfo
= NULL
;
3501 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3503 UINT Hi
= LIGHTMAP_HASHFUNC(Index
);
3504 TRACE("(%p) : for idx(%d)\n", This
, Index
);
3506 LIST_FOR_EACH(e
, &This
->stateBlock
->lightMap
[Hi
]) {
3507 lightInfo
= LIST_ENTRY(e
, PLIGHTINFOEL
, entry
);
3508 if(lightInfo
->OriginalIndex
== Index
) break;
3512 if (lightInfo
== NULL
) {
3513 TRACE("Light enabled state requested but light not defined\n");
3514 return WINED3DERR_INVALIDCALL
;
3516 /* true is 128 according to SetLightEnable */
3517 *pEnable
= lightInfo
->enabled
? 128 : 0;
3522 * Get / Set Clip Planes
3524 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, CONST
float *pPlane
) {
3525 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3526 TRACE("(%p) : for idx %d, %p\n", This
, Index
, pPlane
);
3528 /* Validate Index */
3529 if (Index
>= GL_LIMITS(clipplanes
)) {
3530 TRACE("Application has requested clipplane this device doesn't support\n");
3531 return WINED3DERR_INVALIDCALL
;
3534 This
->updateStateBlock
->changed
.clipplane
|= 1 << Index
;
3536 if(This
->updateStateBlock
->clipplane
[Index
][0] == pPlane
[0] &&
3537 This
->updateStateBlock
->clipplane
[Index
][1] == pPlane
[1] &&
3538 This
->updateStateBlock
->clipplane
[Index
][2] == pPlane
[2] &&
3539 This
->updateStateBlock
->clipplane
[Index
][3] == pPlane
[3]) {
3540 TRACE("Application is setting old values over, nothing to do\n");
3544 This
->updateStateBlock
->clipplane
[Index
][0] = pPlane
[0];
3545 This
->updateStateBlock
->clipplane
[Index
][1] = pPlane
[1];
3546 This
->updateStateBlock
->clipplane
[Index
][2] = pPlane
[2];
3547 This
->updateStateBlock
->clipplane
[Index
][3] = pPlane
[3];
3549 /* Handle recording of state blocks */
3550 if (This
->isRecordingState
) {
3551 TRACE("Recording... not performing anything\n");
3555 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_CLIPPLANE(Index
));
3560 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice
*iface
, DWORD Index
, float *pPlane
) {
3561 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3562 TRACE("(%p) : for idx %d\n", This
, Index
);
3564 /* Validate Index */
3565 if (Index
>= GL_LIMITS(clipplanes
)) {
3566 TRACE("Application has requested clipplane this device doesn't support\n");
3567 return WINED3DERR_INVALIDCALL
;
3570 pPlane
[0] = This
->stateBlock
->clipplane
[Index
][0];
3571 pPlane
[1] = This
->stateBlock
->clipplane
[Index
][1];
3572 pPlane
[2] = This
->stateBlock
->clipplane
[Index
][2];
3573 pPlane
[3] = This
->stateBlock
->clipplane
[Index
][3];
3578 * Get / Set Clip Plane Status
3579 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3581 static HRESULT WINAPI
IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice
*iface
, CONST WINED3DCLIPSTATUS
* pClipStatus
) {
3582 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3583 FIXME("(%p) : stub\n", This
);
3584 if (NULL
== pClipStatus
) {
3585 return WINED3DERR_INVALIDCALL
;
3587 This
->updateStateBlock
->clip_status
.ClipUnion
= pClipStatus
->ClipUnion
;
3588 This
->updateStateBlock
->clip_status
.ClipIntersection
= pClipStatus
->ClipIntersection
;
3592 static HRESULT WINAPI
IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice
*iface
, WINED3DCLIPSTATUS
* pClipStatus
) {
3593 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3594 FIXME("(%p) : stub\n", This
);
3595 if (NULL
== pClipStatus
) {
3596 return WINED3DERR_INVALIDCALL
;
3598 pClipStatus
->ClipUnion
= This
->updateStateBlock
->clip_status
.ClipUnion
;
3599 pClipStatus
->ClipIntersection
= This
->updateStateBlock
->clip_status
.ClipIntersection
;
3604 * Get / Set Material
3606 static HRESULT WINAPI
IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice
*iface
, CONST WINED3DMATERIAL
* pMaterial
) {
3607 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3609 This
->updateStateBlock
->changed
.material
= TRUE
;
3610 This
->updateStateBlock
->material
= *pMaterial
;
3612 /* Handle recording of state blocks */
3613 if (This
->isRecordingState
) {
3614 TRACE("Recording... not performing anything\n");
3618 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_MATERIAL
);
3622 static HRESULT WINAPI
IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice
*iface
, WINED3DMATERIAL
* pMaterial
) {
3623 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3624 *pMaterial
= This
->updateStateBlock
->material
;
3625 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This
, pMaterial
->Diffuse
.r
, pMaterial
->Diffuse
.g
,
3626 pMaterial
->Diffuse
.b
, pMaterial
->Diffuse
.a
);
3627 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This
, pMaterial
->Ambient
.r
, pMaterial
->Ambient
.g
,
3628 pMaterial
->Ambient
.b
, pMaterial
->Ambient
.a
);
3629 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This
, pMaterial
->Specular
.r
, pMaterial
->Specular
.g
,
3630 pMaterial
->Specular
.b
, pMaterial
->Specular
.a
);
3631 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This
, pMaterial
->Emissive
.r
, pMaterial
->Emissive
.g
,
3632 pMaterial
->Emissive
.b
, pMaterial
->Emissive
.a
);
3633 TRACE("(%p) : Power (%f)\n", This
, pMaterial
->Power
);
3641 static HRESULT WINAPI
IWineD3DDeviceImpl_SetIndices(IWineD3DDevice
*iface
, IWineD3DBuffer
* pIndexData
, WINED3DFORMAT fmt
) {
3642 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3643 IWineD3DBuffer
*oldIdxs
;
3645 TRACE("(%p) : Setting to %p\n", This
, pIndexData
);
3646 oldIdxs
= This
->updateStateBlock
->pIndexData
;
3648 This
->updateStateBlock
->changed
.indices
= TRUE
;
3649 This
->updateStateBlock
->pIndexData
= pIndexData
;
3650 This
->updateStateBlock
->IndexFmt
= fmt
;
3652 /* Handle recording of state blocks */
3653 if (This
->isRecordingState
) {
3654 TRACE("Recording... not performing anything\n");
3655 if(pIndexData
) IWineD3DBuffer_AddRef(pIndexData
);
3656 if(oldIdxs
) IWineD3DBuffer_Release(oldIdxs
);
3660 if(oldIdxs
!= pIndexData
) {
3661 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
3663 InterlockedIncrement(&((struct wined3d_buffer
*)pIndexData
)->bind_count
);
3664 IWineD3DBuffer_AddRef(pIndexData
);
3667 InterlockedDecrement(&((struct wined3d_buffer
*)oldIdxs
)->bind_count
);
3668 IWineD3DBuffer_Release(oldIdxs
);
3675 static HRESULT WINAPI
IWineD3DDeviceImpl_GetIndices(IWineD3DDevice
*iface
, IWineD3DBuffer
** ppIndexData
) {
3676 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3678 *ppIndexData
= This
->stateBlock
->pIndexData
;
3680 /* up ref count on ppindexdata */
3682 IWineD3DBuffer_AddRef(*ppIndexData
);
3683 TRACE("(%p) index data set to %p\n", This
, ppIndexData
);
3685 TRACE("(%p) No index data set\n", This
);
3687 TRACE("Returning %p\n", *ppIndexData
);
3692 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3693 static HRESULT WINAPI
IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice
*iface
, INT BaseIndex
) {
3694 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3695 TRACE("(%p)->(%d)\n", This
, BaseIndex
);
3697 if(This
->updateStateBlock
->baseVertexIndex
== BaseIndex
) {
3698 TRACE("Application is setting the old value over, nothing to do\n");
3702 This
->updateStateBlock
->baseVertexIndex
= BaseIndex
;
3704 if (This
->isRecordingState
) {
3705 TRACE("Recording... not performing anything\n");
3708 /* The base vertex index affects the stream sources */
3709 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
3713 static HRESULT WINAPI
IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice
*iface
, INT
* base_index
) {
3714 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3715 TRACE("(%p) : base_index %p\n", This
, base_index
);
3717 *base_index
= This
->stateBlock
->baseVertexIndex
;
3719 TRACE("Returning %u\n", *base_index
);
3725 * Get / Set Viewports
3727 static HRESULT WINAPI
IWineD3DDeviceImpl_SetViewport(IWineD3DDevice
*iface
, CONST WINED3DVIEWPORT
* pViewport
) {
3728 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3730 TRACE("(%p)\n", This
);
3731 This
->updateStateBlock
->changed
.viewport
= TRUE
;
3732 This
->updateStateBlock
->viewport
= *pViewport
;
3734 /* Handle recording of state blocks */
3735 if (This
->isRecordingState
) {
3736 TRACE("Recording... not performing anything\n");
3740 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This
,
3741 pViewport
->X
, pViewport
->Y
, pViewport
->Width
, pViewport
->Height
, pViewport
->MinZ
, pViewport
->MaxZ
);
3743 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VIEWPORT
);
3748 static HRESULT WINAPI
IWineD3DDeviceImpl_GetViewport(IWineD3DDevice
*iface
, WINED3DVIEWPORT
* pViewport
) {
3749 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3750 TRACE("(%p)\n", This
);
3751 *pViewport
= This
->stateBlock
->viewport
;
3756 * Get / Set Render States
3757 * TODO: Verify against dx9 definitions
3759 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice
*iface
, WINED3DRENDERSTATETYPE State
, DWORD Value
) {
3761 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3762 DWORD oldValue
= This
->stateBlock
->renderState
[State
];
3764 TRACE("(%p)->state = %s(%d), value = %d\n", This
, debug_d3drenderstate(State
), State
, Value
);
3766 This
->updateStateBlock
->changed
.renderState
[State
>> 5] |= 1 << (State
& 0x1f);
3767 This
->updateStateBlock
->renderState
[State
] = Value
;
3769 /* Handle recording of state blocks */
3770 if (This
->isRecordingState
) {
3771 TRACE("Recording... not performing anything\n");
3775 /* Compared here and not before the assignment to allow proper stateblock recording */
3776 if(Value
== oldValue
) {
3777 TRACE("Application is setting the old value over, nothing to do\n");
3779 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(State
));
3785 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice
*iface
, WINED3DRENDERSTATETYPE State
, DWORD
*pValue
) {
3786 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3787 TRACE("(%p) for State %d = %d\n", This
, State
, This
->stateBlock
->renderState
[State
]);
3788 *pValue
= This
->stateBlock
->renderState
[State
];
3793 * Get / Set Sampler States
3794 * TODO: Verify against dx9 definitions
3797 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD Value
) {
3798 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3801 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3802 This
, Sampler
, debug_d3dsamplerstate(Type
), Type
, Value
);
3804 if (Sampler
>= WINED3DVERTEXTEXTURESAMPLER0
&& Sampler
<= WINED3DVERTEXTEXTURESAMPLER3
) {
3805 Sampler
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
3808 if (Sampler
>= sizeof(This
->stateBlock
->samplerState
)/sizeof(This
->stateBlock
->samplerState
[0])) {
3809 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler
);
3810 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
3813 * SetSampler is designed to allow for more than the standard up to 8 textures
3814 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3815 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3817 * http://developer.nvidia.com/object/General_FAQ.html#t6
3819 * There are two new settings for GForce
3821 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3822 * and the texture one:
3823 * GL_MAX_TEXTURE_COORDS_ARB.
3824 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3827 oldValue
= This
->stateBlock
->samplerState
[Sampler
][Type
];
3828 This
->updateStateBlock
->samplerState
[Sampler
][Type
] = Value
;
3829 This
->updateStateBlock
->changed
.samplerState
[Sampler
] |= 1 << Type
;
3831 /* Handle recording of state blocks */
3832 if (This
->isRecordingState
) {
3833 TRACE("Recording... not performing anything\n");
3837 if(oldValue
== Value
) {
3838 TRACE("Application is setting the old value over, nothing to do\n");
3842 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(Sampler
));
3847 static HRESULT WINAPI
IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice
*iface
, DWORD Sampler
, WINED3DSAMPLERSTATETYPE Type
, DWORD
* Value
) {
3848 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3850 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3851 This
, Sampler
, debug_d3dsamplerstate(Type
), Type
);
3853 if (Sampler
>= WINED3DVERTEXTEXTURESAMPLER0
&& Sampler
<= WINED3DVERTEXTEXTURESAMPLER3
) {
3854 Sampler
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
3857 if (Sampler
>= sizeof(This
->stateBlock
->samplerState
)/sizeof(This
->stateBlock
->samplerState
[0])) {
3858 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler
);
3859 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
3861 *Value
= This
->stateBlock
->samplerState
[Sampler
][Type
];
3862 TRACE("(%p) : Returning %#x\n", This
, *Value
);
3867 static HRESULT WINAPI
IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice
*iface
, CONST RECT
* pRect
) {
3868 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3870 This
->updateStateBlock
->changed
.scissorRect
= TRUE
;
3871 if(EqualRect(&This
->updateStateBlock
->scissorRect
, pRect
)) {
3872 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3875 CopyRect(&This
->updateStateBlock
->scissorRect
, pRect
);
3877 if(This
->isRecordingState
) {
3878 TRACE("Recording... not performing anything\n");
3882 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SCISSORRECT
);
3887 static HRESULT WINAPI
IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice
*iface
, RECT
* pRect
) {
3888 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3890 *pRect
= This
->updateStateBlock
->scissorRect
;
3891 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This
, pRect
->left
, pRect
->top
, pRect
->right
, pRect
->bottom
);
3895 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
* pDecl
) {
3896 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
3897 IWineD3DVertexDeclaration
*oldDecl
= This
->updateStateBlock
->vertexDecl
;
3899 TRACE("(%p) : pDecl=%p\n", This
, pDecl
);
3901 This
->updateStateBlock
->vertexDecl
= pDecl
;
3902 This
->updateStateBlock
->changed
.vertexDecl
= TRUE
;
3904 if (This
->isRecordingState
) {
3905 TRACE("Recording... not performing anything\n");
3907 } else if(pDecl
== oldDecl
) {
3908 /* Checked after the assignment to allow proper stateblock recording */
3909 TRACE("Application is setting the old declaration over, nothing to do\n");
3913 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
3917 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice
* iface
, IWineD3DVertexDeclaration
** ppDecl
) {
3918 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3920 TRACE("(%p) : ppDecl=%p\n", This
, ppDecl
);
3922 *ppDecl
= This
->stateBlock
->vertexDecl
;
3923 if (NULL
!= *ppDecl
) IWineD3DVertexDeclaration_AddRef(*ppDecl
);
3927 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
* pShader
) {
3928 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3929 IWineD3DVertexShader
* oldShader
= This
->updateStateBlock
->vertexShader
;
3931 This
->updateStateBlock
->vertexShader
= pShader
;
3932 This
->updateStateBlock
->changed
.vertexShader
= TRUE
;
3934 if (This
->isRecordingState
) {
3935 if(pShader
) IWineD3DVertexShader_AddRef(pShader
);
3936 if(oldShader
) IWineD3DVertexShader_Release(oldShader
);
3937 TRACE("Recording... not performing anything\n");
3939 } else if(oldShader
== pShader
) {
3940 /* Checked here to allow proper stateblock recording */
3941 TRACE("App is setting the old shader over, nothing to do\n");
3945 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
3946 if(pShader
) IWineD3DVertexShader_AddRef(pShader
);
3947 if(oldShader
) IWineD3DVertexShader_Release(oldShader
);
3949 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VSHADER
);
3954 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice
*iface
, IWineD3DVertexShader
** ppShader
) {
3955 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3957 if (NULL
== ppShader
) {
3958 return WINED3DERR_INVALIDCALL
;
3960 *ppShader
= This
->stateBlock
->vertexShader
;
3961 if( NULL
!= *ppShader
)
3962 IWineD3DVertexShader_AddRef(*ppShader
);
3964 TRACE("(%p) : returning %p\n", This
, *ppShader
);
3968 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantB(
3969 IWineD3DDevice
*iface
,
3971 CONST BOOL
*srcData
,
3974 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
3975 unsigned int i
, cnt
= min(count
, MAX_CONST_B
- start
);
3977 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3978 iface
, srcData
, start
, count
);
3980 if (!srcData
|| start
>= MAX_CONST_B
) return WINED3DERR_INVALIDCALL
;
3982 memcpy(&This
->updateStateBlock
->vertexShaderConstantB
[start
], srcData
, cnt
* sizeof(BOOL
));
3983 for (i
= 0; i
< cnt
; i
++)
3984 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
3986 for (i
= start
; i
< cnt
+ start
; ++i
) {
3987 This
->updateStateBlock
->changed
.vertexShaderConstantsB
|= (1 << i
);
3990 if (!This
->isRecordingState
) IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
3995 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantB(
3996 IWineD3DDevice
*iface
,
4001 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4002 int cnt
= min(count
, MAX_CONST_B
- start
);
4004 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4005 iface
, dstData
, start
, count
);
4007 if (dstData
== NULL
|| cnt
< 0)
4008 return WINED3DERR_INVALIDCALL
;
4010 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantB
[start
], cnt
* sizeof(BOOL
));
4014 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantI(
4015 IWineD3DDevice
*iface
,
4020 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4021 unsigned int i
, cnt
= min(count
, MAX_CONST_I
- start
);
4023 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4024 iface
, srcData
, start
, count
);
4026 if (!srcData
|| start
>= MAX_CONST_I
) return WINED3DERR_INVALIDCALL
;
4028 memcpy(&This
->updateStateBlock
->vertexShaderConstantI
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
4029 for (i
= 0; i
< cnt
; i
++)
4030 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
4031 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
4033 for (i
= start
; i
< cnt
+ start
; ++i
) {
4034 This
->updateStateBlock
->changed
.vertexShaderConstantsI
|= (1 << i
);
4037 if (!This
->isRecordingState
) IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
4042 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantI(
4043 IWineD3DDevice
*iface
,
4048 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4049 int cnt
= min(count
, MAX_CONST_I
- start
);
4051 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4052 iface
, dstData
, start
, count
);
4054 if (dstData
== NULL
|| ((signed int) MAX_CONST_I
- (signed int) start
) <= (signed int) 0)
4055 return WINED3DERR_INVALIDCALL
;
4057 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantI
[start
* 4], cnt
* sizeof(int) * 4);
4061 static HRESULT WINAPI
IWineD3DDeviceImpl_SetVertexShaderConstantF(
4062 IWineD3DDevice
*iface
,
4064 CONST
float *srcData
,
4067 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4070 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4071 iface
, srcData
, start
, count
);
4073 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4074 if (srcData
== NULL
|| start
+ count
> This
->d3d_vshader_constantF
|| start
> This
->d3d_vshader_constantF
)
4075 return WINED3DERR_INVALIDCALL
;
4077 memcpy(&This
->updateStateBlock
->vertexShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
4079 for (i
= 0; i
< count
; i
++)
4080 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
4081 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
4084 if (!This
->isRecordingState
)
4086 This
->shader_backend
->shader_update_float_vertex_constants(iface
, start
, count
);
4087 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VERTEXSHADERCONSTANT
);
4090 memset(This
->updateStateBlock
->changed
.vertexShaderConstantsF
+ start
, 1,
4091 sizeof(*This
->updateStateBlock
->changed
.vertexShaderConstantsF
) * count
);
4096 static HRESULT WINAPI
IWineD3DDeviceImpl_GetVertexShaderConstantF(
4097 IWineD3DDevice
*iface
,
4102 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4103 int cnt
= min(count
, This
->d3d_vshader_constantF
- start
);
4105 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4106 iface
, dstData
, start
, count
);
4108 if (dstData
== NULL
|| cnt
< 0)
4109 return WINED3DERR_INVALIDCALL
;
4111 memcpy(dstData
, &This
->stateBlock
->vertexShaderConstantF
[start
* 4], cnt
* sizeof(float) * 4);
4115 static inline void markTextureStagesDirty(IWineD3DDeviceImpl
*This
, DWORD stage
) {
4117 for(i
= 0; i
<= WINED3D_HIGHEST_TEXTURE_STATE
; ++i
)
4119 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(stage
, i
));
4123 static void device_map_stage(IWineD3DDeviceImpl
*This
, int stage
, int unit
) {
4124 int i
= This
->rev_tex_unit_map
[unit
];
4125 int j
= This
->texUnitMap
[stage
];
4127 This
->texUnitMap
[stage
] = unit
;
4128 if (i
!= -1 && i
!= stage
) {
4129 This
->texUnitMap
[i
] = -1;
4132 This
->rev_tex_unit_map
[unit
] = stage
;
4133 if (j
!= -1 && j
!= unit
) {
4134 This
->rev_tex_unit_map
[j
] = -1;
4138 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl
*This
) {
4141 This
->fixed_function_usage_map
= 0;
4142 for (i
= 0; i
< MAX_TEXTURES
; ++i
) {
4143 WINED3DTEXTUREOP color_op
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLOROP
];
4144 WINED3DTEXTUREOP alpha_op
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAOP
];
4145 DWORD color_arg1
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG1
] & WINED3DTA_SELECTMASK
;
4146 DWORD color_arg2
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG2
] & WINED3DTA_SELECTMASK
;
4147 DWORD color_arg3
= This
->stateBlock
->textureState
[i
][WINED3DTSS_COLORARG0
] & WINED3DTA_SELECTMASK
;
4148 DWORD alpha_arg1
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG1
] & WINED3DTA_SELECTMASK
;
4149 DWORD alpha_arg2
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG2
] & WINED3DTA_SELECTMASK
;
4150 DWORD alpha_arg3
= This
->stateBlock
->textureState
[i
][WINED3DTSS_ALPHAARG0
] & WINED3DTA_SELECTMASK
;
4152 if (color_op
== WINED3DTOP_DISABLE
) {
4153 /* Not used, and disable higher stages */
4157 if (((color_arg1
== WINED3DTA_TEXTURE
) && color_op
!= WINED3DTOP_SELECTARG2
)
4158 || ((color_arg2
== WINED3DTA_TEXTURE
) && color_op
!= WINED3DTOP_SELECTARG1
)
4159 || ((color_arg3
== WINED3DTA_TEXTURE
) && (color_op
== WINED3DTOP_MULTIPLYADD
|| color_op
== WINED3DTOP_LERP
))
4160 || ((alpha_arg1
== WINED3DTA_TEXTURE
) && alpha_op
!= WINED3DTOP_SELECTARG2
)
4161 || ((alpha_arg2
== WINED3DTA_TEXTURE
) && alpha_op
!= WINED3DTOP_SELECTARG1
)
4162 || ((alpha_arg3
== WINED3DTA_TEXTURE
) && (alpha_op
== WINED3DTOP_MULTIPLYADD
|| alpha_op
== WINED3DTOP_LERP
))) {
4163 This
->fixed_function_usage_map
|= (1 << i
);
4166 if ((color_op
== WINED3DTOP_BUMPENVMAP
|| color_op
== WINED3DTOP_BUMPENVMAPLUMINANCE
) && i
< MAX_TEXTURES
- 1) {
4167 This
->fixed_function_usage_map
|= (1 << (i
+ 1));
4172 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl
*This
) {
4173 unsigned int i
, tex
;
4176 device_update_fixed_function_usage_map(This
);
4177 ffu_map
= This
->fixed_function_usage_map
;
4179 if (This
->max_ffp_textures
== This
->max_ffp_texture_stages
||
4180 This
->stateBlock
->lowest_disabled_stage
<= This
->max_ffp_textures
) {
4181 for (i
= 0; ffu_map
; ffu_map
>>= 1, ++i
)
4183 if (!(ffu_map
& 1)) continue;
4185 if (This
->texUnitMap
[i
] != i
) {
4186 device_map_stage(This
, i
, i
);
4187 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
4188 markTextureStagesDirty(This
, i
);
4194 /* Now work out the mapping */
4196 for (i
= 0; ffu_map
; ffu_map
>>= 1, ++i
)
4198 if (!(ffu_map
& 1)) continue;
4200 if (This
->texUnitMap
[i
] != tex
) {
4201 device_map_stage(This
, i
, tex
);
4202 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
4203 markTextureStagesDirty(This
, i
);
4210 static void device_map_psamplers(IWineD3DDeviceImpl
*This
) {
4211 const DWORD
*sampler_tokens
=
4212 ((IWineD3DPixelShaderImpl
*)This
->stateBlock
->pixelShader
)->baseShader
.reg_maps
.samplers
;
4215 for (i
= 0; i
< MAX_FRAGMENT_SAMPLERS
; ++i
) {
4216 if (sampler_tokens
[i
] && This
->texUnitMap
[i
] != i
) {
4217 device_map_stage(This
, i
, i
);
4218 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(i
));
4219 if (i
< MAX_TEXTURES
) {
4220 markTextureStagesDirty(This
, i
);
4226 static BOOL
device_unit_free_for_vs(IWineD3DDeviceImpl
*This
, const DWORD
*pshader_sampler_tokens
,
4227 const DWORD
*vshader_sampler_tokens
, int unit
)
4229 int current_mapping
= This
->rev_tex_unit_map
[unit
];
4231 if (current_mapping
== -1) {
4232 /* Not currently used */
4236 if (current_mapping
< MAX_FRAGMENT_SAMPLERS
) {
4237 /* Used by a fragment sampler */
4239 if (!pshader_sampler_tokens
) {
4240 /* No pixel shader, check fixed function */
4241 return current_mapping
>= MAX_TEXTURES
|| !(This
->fixed_function_usage_map
& (1 << current_mapping
));
4244 /* Pixel shader, check the shader's sampler map */
4245 return !pshader_sampler_tokens
[current_mapping
];
4248 /* Used by a vertex sampler */
4249 return !vshader_sampler_tokens
[current_mapping
];
4252 static void device_map_vsamplers(IWineD3DDeviceImpl
*This
, BOOL ps
) {
4253 const DWORD
*vshader_sampler_tokens
=
4254 ((IWineD3DVertexShaderImpl
*)This
->stateBlock
->vertexShader
)->baseShader
.reg_maps
.samplers
;
4255 const DWORD
*pshader_sampler_tokens
= NULL
;
4256 int start
= GL_LIMITS(combined_samplers
) - 1;
4260 IWineD3DPixelShaderImpl
*pshader
= (IWineD3DPixelShaderImpl
*)This
->stateBlock
->pixelShader
;
4262 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
4263 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
4264 pshader_sampler_tokens
= pshader
->baseShader
.reg_maps
.samplers
;
4267 for (i
= 0; i
< MAX_VERTEX_SAMPLERS
; ++i
) {
4268 int vsampler_idx
= i
+ MAX_FRAGMENT_SAMPLERS
;
4269 if (vshader_sampler_tokens
[i
]) {
4270 if (This
->texUnitMap
[vsampler_idx
] != WINED3D_UNMAPPED_STAGE
)
4272 /* Already mapped somewhere */
4276 while (start
>= 0) {
4277 if (device_unit_free_for_vs(This
, pshader_sampler_tokens
, vshader_sampler_tokens
, start
)) {
4278 device_map_stage(This
, vsampler_idx
, start
);
4279 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(vsampler_idx
));
4291 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl
*This
) {
4292 BOOL vs
= use_vs(This
->stateBlock
);
4293 BOOL ps
= use_ps(This
->stateBlock
);
4296 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
4297 * that would be really messy and require shader recompilation
4298 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
4299 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
4302 device_map_psamplers(This
);
4304 device_map_fixed_function_samplers(This
);
4308 device_map_vsamplers(This
, ps
);
4312 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
*pShader
) {
4313 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4314 IWineD3DPixelShader
*oldShader
= This
->updateStateBlock
->pixelShader
;
4315 This
->updateStateBlock
->pixelShader
= pShader
;
4316 This
->updateStateBlock
->changed
.pixelShader
= TRUE
;
4318 /* Handle recording of state blocks */
4319 if (This
->isRecordingState
) {
4320 TRACE("Recording... not performing anything\n");
4323 if (This
->isRecordingState
) {
4324 TRACE("Recording... not performing anything\n");
4325 if(pShader
) IWineD3DPixelShader_AddRef(pShader
);
4326 if(oldShader
) IWineD3DPixelShader_Release(oldShader
);
4330 if(pShader
== oldShader
) {
4331 TRACE("App is setting the old pixel shader over, nothing to do\n");
4335 if(pShader
) IWineD3DPixelShader_AddRef(pShader
);
4336 if(oldShader
) IWineD3DPixelShader_Release(oldShader
);
4338 TRACE("(%p) : setting pShader(%p)\n", This
, pShader
);
4339 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADER
);
4344 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice
*iface
, IWineD3DPixelShader
**ppShader
) {
4345 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4347 if (NULL
== ppShader
) {
4348 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This
);
4349 return WINED3DERR_INVALIDCALL
;
4352 *ppShader
= This
->stateBlock
->pixelShader
;
4353 if (NULL
!= *ppShader
) {
4354 IWineD3DPixelShader_AddRef(*ppShader
);
4356 TRACE("(%p) : returning %p\n", This
, *ppShader
);
4360 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantB(
4361 IWineD3DDevice
*iface
,
4363 CONST BOOL
*srcData
,
4366 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4367 unsigned int i
, cnt
= min(count
, MAX_CONST_B
- start
);
4369 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
4370 iface
, srcData
, start
, count
);
4372 if (!srcData
|| start
>= MAX_CONST_B
) return WINED3DERR_INVALIDCALL
;
4374 memcpy(&This
->updateStateBlock
->pixelShaderConstantB
[start
], srcData
, cnt
* sizeof(BOOL
));
4375 for (i
= 0; i
< cnt
; i
++)
4376 TRACE("Set BOOL constant %u to %s\n", start
+ i
, srcData
[i
]? "true":"false");
4378 for (i
= start
; i
< cnt
+ start
; ++i
) {
4379 This
->updateStateBlock
->changed
.pixelShaderConstantsB
|= (1 << i
);
4382 if (!This
->isRecordingState
) IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
4387 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantB(
4388 IWineD3DDevice
*iface
,
4393 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4394 int cnt
= min(count
, MAX_CONST_B
- start
);
4396 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4397 iface
, dstData
, start
, count
);
4399 if (dstData
== NULL
|| cnt
< 0)
4400 return WINED3DERR_INVALIDCALL
;
4402 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantB
[start
], cnt
* sizeof(BOOL
));
4406 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantI(
4407 IWineD3DDevice
*iface
,
4412 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4413 unsigned int i
, cnt
= min(count
, MAX_CONST_I
- start
);
4415 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
4416 iface
, srcData
, start
, count
);
4418 if (!srcData
|| start
>= MAX_CONST_I
) return WINED3DERR_INVALIDCALL
;
4420 memcpy(&This
->updateStateBlock
->pixelShaderConstantI
[start
* 4], srcData
, cnt
* sizeof(int) * 4);
4421 for (i
= 0; i
< cnt
; i
++)
4422 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start
+ i
,
4423 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
4425 for (i
= start
; i
< cnt
+ start
; ++i
) {
4426 This
->updateStateBlock
->changed
.pixelShaderConstantsI
|= (1 << i
);
4429 if (!This
->isRecordingState
) IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
4434 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantI(
4435 IWineD3DDevice
*iface
,
4440 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4441 int cnt
= min(count
, MAX_CONST_I
- start
);
4443 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4444 iface
, dstData
, start
, count
);
4446 if (dstData
== NULL
|| cnt
< 0)
4447 return WINED3DERR_INVALIDCALL
;
4449 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantI
[start
* 4], cnt
* sizeof(int) * 4);
4453 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPixelShaderConstantF(
4454 IWineD3DDevice
*iface
,
4456 CONST
float *srcData
,
4459 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4462 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4463 iface
, srcData
, start
, count
);
4465 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4466 if (srcData
== NULL
|| start
+ count
> This
->d3d_pshader_constantF
|| start
> This
->d3d_pshader_constantF
)
4467 return WINED3DERR_INVALIDCALL
;
4469 memcpy(&This
->updateStateBlock
->pixelShaderConstantF
[start
* 4], srcData
, count
* sizeof(float) * 4);
4471 for (i
= 0; i
< count
; i
++)
4472 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start
+ i
,
4473 srcData
[i
*4], srcData
[i
*4+1], srcData
[i
*4+2], srcData
[i
*4+3]);
4476 if (!This
->isRecordingState
)
4478 This
->shader_backend
->shader_update_float_pixel_constants(iface
, start
, count
);
4479 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADERCONSTANT
);
4482 memset(This
->updateStateBlock
->changed
.pixelShaderConstantsF
+ start
, 1,
4483 sizeof(*This
->updateStateBlock
->changed
.pixelShaderConstantsF
) * count
);
4488 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPixelShaderConstantF(
4489 IWineD3DDevice
*iface
,
4494 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4495 int cnt
= min(count
, This
->d3d_pshader_constantF
- start
);
4497 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4498 iface
, dstData
, start
, count
);
4500 if (dstData
== NULL
|| cnt
< 0)
4501 return WINED3DERR_INVALIDCALL
;
4503 memcpy(dstData
, &This
->stateBlock
->pixelShaderConstantF
[start
* 4], cnt
* sizeof(float) * 4);
4507 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4508 static HRESULT
process_vertices_strided(IWineD3DDeviceImpl
*This
, DWORD dwDestIndex
, DWORD dwCount
,
4509 const struct wined3d_stream_info
*stream_info
, struct wined3d_buffer
*dest
, DWORD dwFlags
,
4512 char *dest_ptr
, *dest_conv
= NULL
, *dest_conv_addr
= NULL
;
4515 WINED3DMATRIX mat
, proj_mat
, view_mat
, world_mat
;
4519 if (stream_info
->elements
[WINED3D_FFP_NORMAL
].data
)
4521 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4524 if (!stream_info
->elements
[WINED3D_FFP_POSITION
].data
)
4526 ERR("Source has no position mask\n");
4527 return WINED3DERR_INVALIDCALL
;
4530 /* We might access VBOs from this code, so hold the lock */
4533 if (dest
->resource
.allocatedMemory
== NULL
) {
4534 /* This may happen if we do direct locking into a vbo. Unlikely,
4535 * but theoretically possible(ddraw processvertices test)
4537 dest
->resource
.allocatedMemory
= HeapAlloc(GetProcessHeap(), 0, dest
->resource
.size
);
4538 if(!dest
->resource
.allocatedMemory
) {
4540 ERR("Out of memory\n");
4541 return E_OUTOFMEMORY
;
4543 if (dest
->buffer_object
)
4546 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, dest
->buffer_object
));
4547 checkGLcall("glBindBufferARB");
4548 src
= GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB
, GL_READ_ONLY_ARB
));
4550 memcpy(dest
->resource
.allocatedMemory
, src
, dest
->resource
.size
);
4552 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB
));
4553 checkGLcall("glUnmapBufferARB");
4557 /* Get a pointer into the destination vbo(create one if none exists) and
4558 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4560 if (!dest
->buffer_object
&& GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT
))
4562 dest
->flags
|= WINED3D_BUFFER_CREATEBO
;
4563 IWineD3DBuffer_PreLoad((IWineD3DBuffer
*)dest
);
4566 if (dest
->buffer_object
)
4568 unsigned char extrabytes
= 0;
4569 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4570 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4571 * this may write 4 extra bytes beyond the area that should be written
4573 if(DestFVF
== WINED3DFVF_XYZ
) extrabytes
= 4;
4574 dest_conv_addr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwCount
* get_flexible_vertex_size(DestFVF
) + extrabytes
);
4575 if(!dest_conv_addr
) {
4576 ERR("Out of memory\n");
4577 /* Continue without storing converted vertices */
4579 dest_conv
= dest_conv_addr
;
4583 * a) WINED3DRS_CLIPPING is enabled
4584 * b) WINED3DVOP_CLIP is passed
4586 if(This
->stateBlock
->renderState
[WINED3DRS_CLIPPING
]) {
4587 static BOOL warned
= FALSE
;
4589 * The clipping code is not quite correct. Some things need
4590 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4591 * so disable clipping for now.
4592 * (The graphics in Half-Life are broken, and my processvertices
4593 * test crashes with IDirect3DDevice3)
4599 FIXME("Clipping is broken and disabled for now\n");
4601 } else doClip
= FALSE
;
4602 dest_ptr
= ((char *) buffer_get_sysmem(dest
)) + dwDestIndex
* get_flexible_vertex_size(DestFVF
);
4604 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
4607 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
4608 WINED3DTS_PROJECTION
,
4610 IWineD3DDevice_GetTransform( (IWineD3DDevice
*) This
,
4611 WINED3DTS_WORLDMATRIX(0),
4614 TRACE("View mat:\n");
4615 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
);
4616 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
);
4617 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
);
4618 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
);
4620 TRACE("Proj mat:\n");
4621 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
);
4622 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
);
4623 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
);
4624 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
);
4626 TRACE("World mat:\n");
4627 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
);
4628 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
);
4629 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
);
4630 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
);
4632 /* Get the viewport */
4633 IWineD3DDevice_GetViewport( (IWineD3DDevice
*) This
, &vp
);
4634 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4635 vp
.X
, vp
.Y
, vp
.Width
, vp
.Height
, vp
.MinZ
, vp
.MaxZ
);
4637 multiply_matrix(&mat
,&view_mat
,&world_mat
);
4638 multiply_matrix(&mat
,&proj_mat
,&mat
);
4640 numTextures
= (DestFVF
& WINED3DFVF_TEXCOUNT_MASK
) >> WINED3DFVF_TEXCOUNT_SHIFT
;
4642 for (i
= 0; i
< dwCount
; i
+= 1) {
4643 unsigned int tex_index
;
4645 if ( ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZ
) ||
4646 ((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) ) {
4647 /* The position first */
4648 const struct wined3d_stream_info_element
*element
= &stream_info
->elements
[WINED3D_FFP_POSITION
];
4649 const float *p
= (const float *)(element
->data
+ i
* element
->stride
);
4651 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p
[0], p
[1], p
[2]);
4653 /* Multiplication with world, view and projection matrix */
4654 x
= (p
[0] * mat
.u
.s
._11
) + (p
[1] * mat
.u
.s
._21
) + (p
[2] * mat
.u
.s
._31
) + (1.0 * mat
.u
.s
._41
);
4655 y
= (p
[0] * mat
.u
.s
._12
) + (p
[1] * mat
.u
.s
._22
) + (p
[2] * mat
.u
.s
._32
) + (1.0 * mat
.u
.s
._42
);
4656 z
= (p
[0] * mat
.u
.s
._13
) + (p
[1] * mat
.u
.s
._23
) + (p
[2] * mat
.u
.s
._33
) + (1.0 * mat
.u
.s
._43
);
4657 rhw
= (p
[0] * mat
.u
.s
._14
) + (p
[1] * mat
.u
.s
._24
) + (p
[2] * mat
.u
.s
._34
) + (1.0 * mat
.u
.s
._44
);
4659 TRACE("x=%f y=%f z=%f rhw=%f\n", x
, y
, z
, rhw
);
4661 /* WARNING: The following things are taken from d3d7 and were not yet checked
4662 * against d3d8 or d3d9!
4665 /* Clipping conditions: From msdn
4667 * A vertex is clipped if it does not match the following requirements
4671 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4673 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4674 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4679 ( (-rhw
-eps
< x
) && (-rhw
-eps
< y
) && ( -eps
< z
) &&
4680 (x
<= rhw
+ eps
) && (y
<= rhw
+ eps
) && (z
<= rhw
+ eps
) &&
4683 /* "Normal" viewport transformation (not clipped)
4684 * 1) The values are divided by rhw
4685 * 2) The y axis is negative, so multiply it with -1
4686 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4687 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4688 * 4) Multiply x with Width/2 and add Width/2
4689 * 5) The same for the height
4690 * 6) Add the viewpoint X and Y to the 2D coordinates and
4691 * The minimum Z value to z
4692 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4694 * Well, basically it's simply a linear transformation into viewport
4706 z
*= vp
.MaxZ
- vp
.MinZ
;
4708 x
+= vp
.Width
/ 2 + vp
.X
;
4709 y
+= vp
.Height
/ 2 + vp
.Y
;
4714 /* That vertex got clipped
4715 * Contrary to OpenGL it is not dropped completely, it just
4716 * undergoes a different calculation.
4718 TRACE("Vertex got clipped\n");
4725 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4726 * outside of the main vertex buffer memory. That needs some more
4731 TRACE("Writing (%f %f %f) %f\n", x
, y
, z
, rhw
);
4734 ( (float *) dest_ptr
)[0] = x
;
4735 ( (float *) dest_ptr
)[1] = y
;
4736 ( (float *) dest_ptr
)[2] = z
;
4737 ( (float *) dest_ptr
)[3] = rhw
; /* SIC, see ddraw test! */
4739 dest_ptr
+= 3 * sizeof(float);
4741 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
4742 dest_ptr
+= sizeof(float);
4747 ( (float *) dest_conv
)[0] = x
* w
;
4748 ( (float *) dest_conv
)[1] = y
* w
;
4749 ( (float *) dest_conv
)[2] = z
* w
;
4750 ( (float *) dest_conv
)[3] = w
;
4752 dest_conv
+= 3 * sizeof(float);
4754 if((DestFVF
& WINED3DFVF_POSITION_MASK
) == WINED3DFVF_XYZRHW
) {
4755 dest_conv
+= sizeof(float);
4759 if (DestFVF
& WINED3DFVF_PSIZE
) {
4760 dest_ptr
+= sizeof(DWORD
);
4761 if(dest_conv
) dest_conv
+= sizeof(DWORD
);
4763 if (DestFVF
& WINED3DFVF_NORMAL
) {
4764 const struct wined3d_stream_info_element
*element
= &stream_info
->elements
[WINED3D_FFP_NORMAL
];
4765 const float *normal
= (const float *)(element
->data
+ i
* element
->stride
);
4766 /* AFAIK this should go into the lighting information */
4767 FIXME("Didn't expect the destination to have a normal\n");
4768 copy_and_next(dest_ptr
, normal
, 3 * sizeof(float));
4770 copy_and_next(dest_conv
, normal
, 3 * sizeof(float));
4774 if (DestFVF
& WINED3DFVF_DIFFUSE
) {
4775 const struct wined3d_stream_info_element
*element
= &stream_info
->elements
[WINED3D_FFP_DIFFUSE
];
4776 const DWORD
*color_d
= (const DWORD
*)(element
->data
+ i
* element
->stride
);
4778 static BOOL warned
= FALSE
;
4781 ERR("No diffuse color in source, but destination has one\n");
4785 *( (DWORD
*) dest_ptr
) = 0xffffffff;
4786 dest_ptr
+= sizeof(DWORD
);
4789 *( (DWORD
*) dest_conv
) = 0xffffffff;
4790 dest_conv
+= sizeof(DWORD
);
4794 copy_and_next(dest_ptr
, color_d
, sizeof(DWORD
));
4796 *( (DWORD
*) dest_conv
) = (*color_d
& 0xff00ff00) ; /* Alpha + green */
4797 *( (DWORD
*) dest_conv
) |= (*color_d
& 0x00ff0000) >> 16; /* Red */
4798 *( (DWORD
*) dest_conv
) |= (*color_d
& 0xff0000ff) << 16; /* Blue */
4799 dest_conv
+= sizeof(DWORD
);
4804 if (DestFVF
& WINED3DFVF_SPECULAR
) {
4805 /* What's the color value in the feedback buffer? */
4806 const struct wined3d_stream_info_element
*element
= &stream_info
->elements
[WINED3D_FFP_SPECULAR
];
4807 const DWORD
*color_s
= (const DWORD
*)(element
->data
+ i
* element
->stride
);
4809 static BOOL warned
= FALSE
;
4812 ERR("No specular color in source, but destination has one\n");
4816 *( (DWORD
*) dest_ptr
) = 0xFF000000;
4817 dest_ptr
+= sizeof(DWORD
);
4820 *( (DWORD
*) dest_conv
) = 0xFF000000;
4821 dest_conv
+= sizeof(DWORD
);
4825 copy_and_next(dest_ptr
, color_s
, sizeof(DWORD
));
4827 *( (DWORD
*) dest_conv
) = (*color_s
& 0xff00ff00) ; /* Alpha + green */
4828 *( (DWORD
*) dest_conv
) |= (*color_s
& 0x00ff0000) >> 16; /* Red */
4829 *( (DWORD
*) dest_conv
) |= (*color_s
& 0xff0000ff) << 16; /* Blue */
4830 dest_conv
+= sizeof(DWORD
);
4835 for (tex_index
= 0; tex_index
< numTextures
; tex_index
++) {
4836 const struct wined3d_stream_info_element
*element
= &stream_info
->elements
[WINED3D_FFP_TEXCOORD0
+ tex_index
];
4837 const float *tex_coord
= (const float *)(element
->data
+ i
* element
->stride
);
4839 ERR("No source texture, but destination requests one\n");
4840 dest_ptr
+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
4841 if(dest_conv
) dest_conv
+= GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float);
4844 copy_and_next(dest_ptr
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
4846 copy_and_next(dest_conv
, tex_coord
, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF
, tex_index
) * sizeof(float));
4853 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB
, dest
->buffer_object
));
4854 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4855 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB
, dwDestIndex
* get_flexible_vertex_size(DestFVF
),
4856 dwCount
* get_flexible_vertex_size(DestFVF
),
4858 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4859 HeapFree(GetProcessHeap(), 0, dest_conv_addr
);
4866 #undef copy_and_next
4868 static HRESULT WINAPI
IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice
*iface
, UINT SrcStartIndex
, UINT DestIndex
,
4869 UINT VertexCount
, IWineD3DBuffer
*pDestBuffer
, IWineD3DVertexDeclaration
*pVertexDecl
, DWORD Flags
,
4872 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4873 struct wined3d_stream_info stream_info
;
4874 BOOL vbo
= FALSE
, streamWasUP
= This
->stateBlock
->streamIsUP
;
4875 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This
, SrcStartIndex
, DestIndex
, VertexCount
, pDestBuffer
, pVertexDecl
, Flags
);
4878 ERR("Output vertex declaration not implemented yet\n");
4881 /* Need any context to write to the vbo. */
4882 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
4884 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4885 * control the streamIsUP flag, thus restore it afterwards.
4887 This
->stateBlock
->streamIsUP
= FALSE
;
4888 device_stream_info_from_declaration(This
, FALSE
, &stream_info
, &vbo
);
4889 This
->stateBlock
->streamIsUP
= streamWasUP
;
4891 if(vbo
|| SrcStartIndex
) {
4893 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4894 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4896 * Also get the start index in, but only loop over all elements if there's something to add at all.
4898 for (i
= 0; i
< (sizeof(stream_info
.elements
) / sizeof(*stream_info
.elements
)); ++i
)
4900 struct wined3d_stream_info_element
*e
= &stream_info
.elements
[i
];
4901 if (e
->buffer_object
)
4903 struct wined3d_buffer
*vb
= (struct wined3d_buffer
*)This
->stateBlock
->streamSource
[e
->stream_idx
];
4904 e
->buffer_object
= 0;
4905 e
->data
= (BYTE
*)((unsigned long)e
->data
+ (unsigned long)buffer_get_sysmem(vb
));
4907 GL_EXTCALL(glDeleteBuffersARB(1, &vb
->buffer_object
));
4908 vb
->buffer_object
= 0;
4911 if (e
->data
) e
->data
+= e
->stride
* SrcStartIndex
;
4915 return process_vertices_strided(This
, DestIndex
, VertexCount
, &stream_info
,
4916 (struct wined3d_buffer
*)pDestBuffer
, Flags
, DestFVF
);
4920 * Get / Set Texture Stage States
4921 * TODO: Verify against dx9 definitions
4923 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD Value
) {
4924 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4925 DWORD oldValue
= This
->updateStateBlock
->textureState
[Stage
][Type
];
4927 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This
, Stage
, debug_d3dtexturestate(Type
), Type
, Value
);
4929 if (Stage
>= MAX_TEXTURES
) {
4930 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage
, MAX_TEXTURES
- 1);
4934 This
->updateStateBlock
->changed
.textureState
[Stage
] |= 1 << Type
;
4935 This
->updateStateBlock
->textureState
[Stage
][Type
] = Value
;
4937 if (This
->isRecordingState
) {
4938 TRACE("Recording... not performing anything\n");
4942 /* Checked after the assignments to allow proper stateblock recording */
4943 if(oldValue
== Value
) {
4944 TRACE("App is setting the old value over, nothing to do\n");
4948 if(Stage
> This
->stateBlock
->lowest_disabled_stage
&&
4949 This
->StateTable
[STATE_TEXTURESTAGE(0, Type
)].representative
== STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP
)) {
4950 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4951 * Changes in other states are important on disabled stages too
4956 if(Type
== WINED3DTSS_COLOROP
) {
4959 if(Value
== WINED3DTOP_DISABLE
&& oldValue
!= WINED3DTOP_DISABLE
) {
4960 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4961 * they have to be disabled
4963 * The current stage is dirtified below.
4965 for(i
= Stage
+ 1; i
< This
->stateBlock
->lowest_disabled_stage
; i
++) {
4966 TRACE("Additionally dirtifying stage %u\n", i
);
4967 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
4969 This
->stateBlock
->lowest_disabled_stage
= Stage
;
4970 TRACE("New lowest disabled: %u\n", Stage
);
4971 } else if(Value
!= WINED3DTOP_DISABLE
&& oldValue
== WINED3DTOP_DISABLE
) {
4972 /* Previously disabled stage enabled. Stages above it may need enabling
4973 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4974 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4976 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4979 for(i
= Stage
+ 1; i
< GL_LIMITS(texture_stages
); i
++) {
4980 if(This
->updateStateBlock
->textureState
[i
][WINED3DTSS_COLOROP
] == WINED3DTOP_DISABLE
) {
4983 TRACE("Additionally dirtifying stage %u due to enable\n", i
);
4984 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(i
, WINED3DTSS_COLOROP
));
4986 This
->stateBlock
->lowest_disabled_stage
= i
;
4987 TRACE("New lowest disabled: %u\n", i
);
4991 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, Type
));
4996 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice
*iface
, DWORD Stage
, WINED3DTEXTURESTAGESTATETYPE Type
, DWORD
* pValue
) {
4997 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
4998 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This
, Stage
, Type
, This
->updateStateBlock
->textureState
[Stage
][Type
]);
4999 *pValue
= This
->updateStateBlock
->textureState
[Stage
][Type
];
5006 static HRESULT WINAPI
IWineD3DDeviceImpl_SetTexture(IWineD3DDevice
*iface
, DWORD Stage
, IWineD3DBaseTexture
* pTexture
) {
5007 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5008 IWineD3DBaseTexture
*oldTexture
;
5010 TRACE("(%p) : Stage %#x, Texture %p\n", This
, Stage
, pTexture
);
5012 if (Stage
>= WINED3DVERTEXTEXTURESAMPLER0
&& Stage
<= WINED3DVERTEXTEXTURESAMPLER3
) {
5013 Stage
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
5016 if (Stage
>= sizeof(This
->stateBlock
->textures
)/sizeof(This
->stateBlock
->textures
[0])) {
5017 ERR("Current stage overflows textures array (stage %d)\n", Stage
);
5018 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
5021 oldTexture
= This
->updateStateBlock
->textures
[Stage
];
5023 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
5024 if (pTexture
&& ((IWineD3DTextureImpl
*)pTexture
)->resource
.pool
== WINED3DPOOL_SCRATCH
)
5026 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture
);
5027 return WINED3DERR_INVALIDCALL
;
5030 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages
));
5031 TRACE("(%p) : oldtexture(%p)\n", This
,oldTexture
);
5033 This
->updateStateBlock
->changed
.textures
|= 1 << Stage
;
5034 TRACE("(%p) : setting new texture to %p\n", This
, pTexture
);
5035 This
->updateStateBlock
->textures
[Stage
] = pTexture
;
5037 /* Handle recording of state blocks */
5038 if (This
->isRecordingState
) {
5039 TRACE("Recording... not performing anything\n");
5043 if(oldTexture
== pTexture
) {
5044 TRACE("App is setting the same texture again, nothing to do\n");
5048 /** NOTE: MSDN says that setTexture increases the reference count,
5049 * and that the application must set the texture back to null (or have a leaky application),
5050 * This means we should pass the refcount up to the parent
5051 *******************************/
5052 if (NULL
!= This
->updateStateBlock
->textures
[Stage
]) {
5053 IWineD3DBaseTextureImpl
*new = (IWineD3DBaseTextureImpl
*) This
->updateStateBlock
->textures
[Stage
];
5054 ULONG bindCount
= InterlockedIncrement(&new->baseTexture
.bindCount
);
5055 UINT dimensions
= IWineD3DBaseTexture_GetTextureDimensions(pTexture
);
5057 IWineD3DBaseTexture_AddRef(This
->updateStateBlock
->textures
[Stage
]);
5059 if (!oldTexture
|| dimensions
!= IWineD3DBaseTexture_GetTextureDimensions(oldTexture
))
5061 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_PIXELSHADER
);
5064 if(oldTexture
== NULL
&& Stage
< MAX_TEXTURES
) {
5065 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
5066 * so the COLOROP and ALPHAOP have to be dirtified.
5068 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_COLOROP
));
5069 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_ALPHAOP
));
5071 if(bindCount
== 1) {
5072 new->baseTexture
.sampler
= Stage
;
5074 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
5078 if (NULL
!= oldTexture
) {
5079 IWineD3DBaseTextureImpl
*old
= (IWineD3DBaseTextureImpl
*) oldTexture
;
5080 LONG bindCount
= InterlockedDecrement(&old
->baseTexture
.bindCount
);
5082 IWineD3DBaseTexture_Release(oldTexture
);
5083 if(pTexture
== NULL
&& Stage
< MAX_TEXTURES
) {
5084 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_COLOROP
));
5085 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_TEXTURESTAGE(Stage
, WINED3DTSS_ALPHAOP
));
5088 if(bindCount
&& old
->baseTexture
.sampler
== Stage
) {
5090 /* Have to do a search for the other sampler(s) where the texture is bound to
5091 * Shouldn't happen as long as apps bind a texture only to one stage
5093 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
5094 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++) {
5095 if(This
->updateStateBlock
->textures
[i
] == oldTexture
) {
5096 old
->baseTexture
.sampler
= i
;
5103 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(Stage
));
5108 static HRESULT WINAPI
IWineD3DDeviceImpl_GetTexture(IWineD3DDevice
*iface
, DWORD Stage
, IWineD3DBaseTexture
** ppTexture
) {
5109 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5111 TRACE("(%p) : Stage %#x, ppTexture %p\n", This
, Stage
, ppTexture
);
5113 if (Stage
>= WINED3DVERTEXTEXTURESAMPLER0
&& Stage
<= WINED3DVERTEXTEXTURESAMPLER3
) {
5114 Stage
-= (WINED3DVERTEXTEXTURESAMPLER0
- MAX_FRAGMENT_SAMPLERS
);
5117 if (Stage
>= sizeof(This
->stateBlock
->textures
)/sizeof(This
->stateBlock
->textures
[0])) {
5118 ERR("Current stage overflows textures array (stage %d)\n", Stage
);
5119 return WINED3D_OK
; /* Windows accepts overflowing this array ... we do not. */
5122 *ppTexture
=This
->stateBlock
->textures
[Stage
];
5124 IWineD3DBaseTexture_AddRef(*ppTexture
);
5126 TRACE("(%p) : Returning %p\n", This
, *ppTexture
);
5134 static HRESULT WINAPI
IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice
*iface
, UINT iSwapChain
, UINT BackBuffer
, WINED3DBACKBUFFER_TYPE Type
,
5135 IWineD3DSurface
**ppBackBuffer
) {
5136 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5137 IWineD3DSwapChain
*swapChain
;
5140 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This
, BackBuffer
, Type
, iSwapChain
, *ppBackBuffer
);
5142 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
5143 if (hr
== WINED3D_OK
) {
5144 hr
= IWineD3DSwapChain_GetBackBuffer(swapChain
, BackBuffer
, Type
, ppBackBuffer
);
5145 IWineD3DSwapChain_Release(swapChain
);
5147 *ppBackBuffer
= NULL
;
5152 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice
*iface
, WINED3DCAPS
* pCaps
) {
5153 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5154 WARN("(%p) : stub, calling idirect3d for now\n", This
);
5155 return IWineD3D_GetDeviceCaps(This
->wineD3D
, This
->adapterNo
, This
->devType
, pCaps
);
5158 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DDISPLAYMODE
* pMode
) {
5159 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5160 IWineD3DSwapChain
*swapChain
;
5163 if(iSwapChain
> 0) {
5164 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
5165 if (hr
== WINED3D_OK
) {
5166 hr
= IWineD3DSwapChain_GetDisplayMode(swapChain
, pMode
);
5167 IWineD3DSwapChain_Release(swapChain
);
5169 FIXME("(%p) Error getting display mode\n", This
);
5172 /* Don't read the real display mode,
5173 but return the stored mode instead. X11 can't change the color
5174 depth, and some apps are pretty angry if they SetDisplayMode from
5175 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
5177 Also don't relay to the swapchain because with ddraw it's possible
5178 that there isn't a swapchain at all */
5179 pMode
->Width
= This
->ddraw_width
;
5180 pMode
->Height
= This
->ddraw_height
;
5181 pMode
->Format
= This
->ddraw_format
;
5182 pMode
->RefreshRate
= 0;
5190 * Stateblock related functions
5193 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice
*iface
) {
5194 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5195 IWineD3DStateBlock
*stateblock
;
5198 TRACE("(%p)\n", This
);
5200 if (This
->isRecordingState
) return WINED3DERR_INVALIDCALL
;
5202 hr
= IWineD3DDeviceImpl_CreateStateBlock(iface
, WINED3DSBT_RECORDED
, &stateblock
, NULL
);
5203 if (FAILED(hr
)) return hr
;
5205 IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
);
5206 This
->updateStateBlock
= (IWineD3DStateBlockImpl
*)stateblock
;
5207 This
->isRecordingState
= TRUE
;
5209 TRACE("(%p) recording stateblock %p\n", This
, stateblock
);
5214 static HRESULT WINAPI
IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice
*iface
, IWineD3DStateBlock
** ppStateBlock
) {
5215 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5217 IWineD3DStateBlockImpl
*object
= This
->updateStateBlock
;
5219 if (!This
->isRecordingState
) {
5220 WARN("(%p) not recording! returning error\n", This
);
5221 *ppStateBlock
= NULL
;
5222 return WINED3DERR_INVALIDCALL
;
5225 for (i
= 0; i
<= WINEHIGHEST_RENDER_STATE
>> 5; ++i
)
5227 DWORD map
= object
->changed
.renderState
[i
];
5228 for (j
= 0; map
; map
>>= 1, ++j
)
5230 if (!(map
& 1)) continue;
5232 object
->contained_render_states
[object
->num_contained_render_states
++] = (i
<< 5) | j
;
5236 for (i
= 0; i
<= HIGHEST_TRANSFORMSTATE
>> 5; ++i
)
5238 DWORD map
= object
->changed
.transform
[i
];
5239 for (j
= 0; map
; map
>>= 1, ++j
)
5241 if (!(map
& 1)) continue;
5243 object
->contained_transform_states
[object
->num_contained_transform_states
++] = (i
<< 5) | j
;
5246 for(i
= 0; i
< GL_LIMITS(vshader_constantsF
); i
++) {
5247 if(object
->changed
.vertexShaderConstantsF
[i
]) {
5248 object
->contained_vs_consts_f
[object
->num_contained_vs_consts_f
] = i
;
5249 object
->num_contained_vs_consts_f
++;
5252 for(i
= 0; i
< MAX_CONST_I
; i
++) {
5253 if (object
->changed
.vertexShaderConstantsI
& (1 << i
))
5255 object
->contained_vs_consts_i
[object
->num_contained_vs_consts_i
] = i
;
5256 object
->num_contained_vs_consts_i
++;
5259 for(i
= 0; i
< MAX_CONST_B
; i
++) {
5260 if (object
->changed
.vertexShaderConstantsB
& (1 << i
))
5262 object
->contained_vs_consts_b
[object
->num_contained_vs_consts_b
] = i
;
5263 object
->num_contained_vs_consts_b
++;
5266 for (i
= 0; i
< GL_LIMITS(pshader_constantsF
); ++i
)
5268 if (object
->changed
.pixelShaderConstantsF
[i
])
5270 object
->contained_ps_consts_f
[object
->num_contained_ps_consts_f
] = i
;
5271 ++object
->num_contained_ps_consts_f
;
5274 for(i
= 0; i
< MAX_CONST_I
; i
++) {
5275 if (object
->changed
.pixelShaderConstantsI
& (1 << i
))
5277 object
->contained_ps_consts_i
[object
->num_contained_ps_consts_i
] = i
;
5278 object
->num_contained_ps_consts_i
++;
5281 for(i
= 0; i
< MAX_CONST_B
; i
++) {
5282 if (object
->changed
.pixelShaderConstantsB
& (1 << i
))
5284 object
->contained_ps_consts_b
[object
->num_contained_ps_consts_b
] = i
;
5285 object
->num_contained_ps_consts_b
++;
5288 for(i
= 0; i
< MAX_TEXTURES
; i
++) {
5289 DWORD map
= object
->changed
.textureState
[i
];
5291 for(j
= 0; map
; map
>>= 1, ++j
)
5293 if (!(map
& 1)) continue;
5295 object
->contained_tss_states
[object
->num_contained_tss_states
].stage
= i
;
5296 object
->contained_tss_states
[object
->num_contained_tss_states
].state
= j
;
5297 ++object
->num_contained_tss_states
;
5300 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++){
5301 DWORD map
= object
->changed
.samplerState
[i
];
5303 for (j
= 0; map
; map
>>= 1, ++j
)
5305 if (!(map
& 1)) continue;
5307 object
->contained_sampler_states
[object
->num_contained_sampler_states
].stage
= i
;
5308 object
->contained_sampler_states
[object
->num_contained_sampler_states
].state
= j
;
5309 ++object
->num_contained_sampler_states
;
5313 *ppStateBlock
= (IWineD3DStateBlock
*) object
;
5314 This
->isRecordingState
= FALSE
;
5315 This
->updateStateBlock
= This
->stateBlock
;
5316 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
5317 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
5318 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This
, *ppStateBlock
);
5323 * Scene related functions
5325 static HRESULT WINAPI
IWineD3DDeviceImpl_BeginScene(IWineD3DDevice
*iface
) {
5326 /* At the moment we have no need for any functionality at the beginning
5328 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5329 TRACE("(%p)\n", This
);
5332 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
5333 return WINED3DERR_INVALIDCALL
;
5335 This
->inScene
= TRUE
;
5339 static HRESULT WINAPI
IWineD3DDeviceImpl_EndScene(IWineD3DDevice
*iface
) {
5340 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5341 TRACE("(%p)\n", This
);
5343 if(!This
->inScene
) {
5344 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
5345 return WINED3DERR_INVALIDCALL
;
5348 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
5349 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
5351 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
5355 This
->inScene
= FALSE
;
5359 static HRESULT WINAPI
IWineD3DDeviceImpl_Present(IWineD3DDevice
*iface
,
5360 CONST RECT
* pSourceRect
, CONST RECT
* pDestRect
,
5361 HWND hDestWindowOverride
, CONST RGNDATA
* pDirtyRegion
) {
5362 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5363 IWineD3DSwapChain
*swapChain
= NULL
;
5365 int swapchains
= IWineD3DDeviceImpl_GetNumberOfSwapChains(iface
);
5367 TRACE("(%p) Presenting the frame\n", This
);
5369 for(i
= 0 ; i
< swapchains
; i
++) {
5371 IWineD3DDeviceImpl_GetSwapChain(iface
, i
, &swapChain
);
5372 TRACE("presentinng chain %d, %p\n", i
, swapChain
);
5373 IWineD3DSwapChain_Present(swapChain
, pSourceRect
, pDestRect
, hDestWindowOverride
, pDirtyRegion
, 0);
5374 IWineD3DSwapChain_Release(swapChain
);
5380 /* Not called from the VTable (internal subroutine) */
5381 HRESULT
IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl
*This
, IWineD3DSurfaceImpl
*target
, DWORD Count
,
5382 CONST WINED3DRECT
* pRects
, DWORD Flags
, WINED3DCOLOR Color
,
5383 float Z
, DWORD Stencil
) {
5384 GLbitfield glMask
= 0;
5386 WINED3DRECT curRect
;
5388 const WINED3DVIEWPORT
*vp
= &This
->stateBlock
->viewport
;
5389 UINT drawable_width
, drawable_height
;
5390 IWineD3DSurfaceImpl
*depth_stencil
= (IWineD3DSurfaceImpl
*) This
->stencilBufferTarget
;
5391 IWineD3DSwapChainImpl
*swapchain
= NULL
;
5393 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5394 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5395 * for the cleared parts, and the untouched parts.
5397 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5398 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5399 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5400 * checking all this if the dest surface is in the drawable anyway.
5402 if((Flags
& WINED3DCLEAR_TARGET
) && !(target
->Flags
& SFLAG_INDRAWABLE
)) {
5404 if(vp
->X
!= 0 || vp
->Y
!= 0 ||
5405 vp
->Width
< target
->currentDesc
.Width
|| vp
->Height
< target
->currentDesc
.Height
) {
5406 IWineD3DSurface_LoadLocation((IWineD3DSurface
*) target
, SFLAG_INDRAWABLE
, NULL
);
5409 if(This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
] && (
5410 This
->stateBlock
->scissorRect
.left
> 0 || This
->stateBlock
->scissorRect
.top
> 0 ||
5411 This
->stateBlock
->scissorRect
.right
< target
->currentDesc
.Width
||
5412 This
->stateBlock
->scissorRect
.bottom
< target
->currentDesc
.Height
)) {
5413 IWineD3DSurface_LoadLocation((IWineD3DSurface
*) target
, SFLAG_INDRAWABLE
, NULL
);
5416 if(Count
> 0 && pRects
&& (
5417 pRects
[0].x1
> 0 || pRects
[0].y1
> 0 ||
5418 pRects
[0].x2
< target
->currentDesc
.Width
||
5419 pRects
[0].y2
< target
->currentDesc
.Height
)) {
5420 IWineD3DSurface_LoadLocation((IWineD3DSurface
*) target
, SFLAG_INDRAWABLE
, NULL
);
5427 target
->get_drawable_size(target
, &drawable_width
, &drawable_height
);
5429 ActivateContext(This
, (IWineD3DSurface
*) target
, CTXUSAGE_CLEAR
);
5432 /* Only set the values up once, as they are not changing */
5433 if (Flags
& WINED3DCLEAR_STENCIL
) {
5434 glClearStencil(Stencil
);
5435 checkGLcall("glClearStencil");
5436 glMask
= glMask
| GL_STENCIL_BUFFER_BIT
;
5437 glStencilMask(0xFFFFFFFF);
5440 if (Flags
& WINED3DCLEAR_ZBUFFER
) {
5441 DWORD location
= This
->render_offscreen
? SFLAG_DS_OFFSCREEN
: SFLAG_DS_ONSCREEN
;
5442 glDepthMask(GL_TRUE
);
5444 checkGLcall("glClearDepth");
5445 glMask
= glMask
| GL_DEPTH_BUFFER_BIT
;
5446 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ZWRITEENABLE
));
5448 if (vp
->X
!= 0 || vp
->Y
!= 0 ||
5449 vp
->Width
< depth_stencil
->currentDesc
.Width
|| vp
->Height
< depth_stencil
->currentDesc
.Height
) {
5450 surface_load_ds_location(This
->stencilBufferTarget
, location
);
5452 else if (This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
] && (
5453 This
->stateBlock
->scissorRect
.left
> 0 || This
->stateBlock
->scissorRect
.top
> 0 ||
5454 This
->stateBlock
->scissorRect
.right
< depth_stencil
->currentDesc
.Width
||
5455 This
->stateBlock
->scissorRect
.bottom
< depth_stencil
->currentDesc
.Height
)) {
5456 surface_load_ds_location(This
->stencilBufferTarget
, location
);
5458 else if (Count
> 0 && pRects
&& (
5459 pRects
[0].x1
> 0 || pRects
[0].y1
> 0 ||
5460 pRects
[0].x2
< depth_stencil
->currentDesc
.Width
||
5461 pRects
[0].y2
< depth_stencil
->currentDesc
.Height
)) {
5462 surface_load_ds_location(This
->stencilBufferTarget
, location
);
5466 if (Flags
& WINED3DCLEAR_TARGET
) {
5467 TRACE("Clearing screen with glClear to color %x\n", Color
);
5468 glClearColor(D3DCOLOR_R(Color
),
5472 checkGLcall("glClearColor");
5474 /* Clear ALL colors! */
5475 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
5476 glMask
= glMask
| GL_COLOR_BUFFER_BIT
;
5479 vp_rect
.left
= vp
->X
;
5480 vp_rect
.top
= vp
->Y
;
5481 vp_rect
.right
= vp
->X
+ vp
->Width
;
5482 vp_rect
.bottom
= vp
->Y
+ vp
->Height
;
5483 if (!(Count
> 0 && pRects
)) {
5484 if(This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
]) {
5485 IntersectRect(&vp_rect
, &vp_rect
, &This
->stateBlock
->scissorRect
);
5487 if(This
->render_offscreen
) {
5488 glScissor(vp_rect
.left
, vp_rect
.top
,
5489 vp_rect
.right
- vp_rect
.left
, vp_rect
.bottom
- vp_rect
.top
);
5491 glScissor(vp_rect
.left
, drawable_height
- vp_rect
.bottom
,
5492 vp_rect
.right
- vp_rect
.left
, vp_rect
.bottom
- vp_rect
.top
);
5494 checkGLcall("glScissor");
5496 checkGLcall("glClear");
5498 /* Now process each rect in turn */
5499 for (i
= 0; i
< Count
; i
++) {
5500 /* Note gl uses lower left, width/height */
5501 IntersectRect((RECT
*)&curRect
, &vp_rect
, (const RECT
*)&pRects
[i
]);
5502 if(This
->stateBlock
->renderState
[WINED3DRS_SCISSORTESTENABLE
]) {
5503 IntersectRect((RECT
*) &curRect
, (RECT
*) &curRect
, &This
->stateBlock
->scissorRect
);
5505 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This
,
5506 pRects
[i
].x1
, pRects
[i
].y1
, pRects
[i
].x2
, pRects
[i
].y2
,
5507 curRect
.x1
, (target
->currentDesc
.Height
- curRect
.y2
),
5508 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
5510 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5511 * The rectangle is not cleared, no error is returned, but further rectanlges are
5512 * still cleared if they are valid
5514 if(curRect
.x1
> curRect
.x2
|| curRect
.y1
> curRect
.y2
) {
5515 TRACE("Rectangle with negative dimensions, ignoring\n");
5519 if(This
->render_offscreen
) {
5520 glScissor(curRect
.x1
, curRect
.y1
,
5521 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
5523 glScissor(curRect
.x1
, drawable_height
- curRect
.y2
,
5524 curRect
.x2
- curRect
.x1
, curRect
.y2
- curRect
.y1
);
5526 checkGLcall("glScissor");
5529 checkGLcall("glClear");
5533 /* Restore the old values (why..?) */
5534 if (Flags
& WINED3DCLEAR_STENCIL
) {
5535 glStencilMask(This
->stateBlock
->renderState
[WINED3DRS_STENCILWRITEMASK
]);
5537 if (Flags
& WINED3DCLEAR_TARGET
) {
5538 DWORD mask
= This
->stateBlock
->renderState
[WINED3DRS_COLORWRITEENABLE
];
5539 glColorMask(mask
& WINED3DCOLORWRITEENABLE_RED
? GL_TRUE
: GL_FALSE
,
5540 mask
& WINED3DCOLORWRITEENABLE_GREEN
? GL_TRUE
: GL_FALSE
,
5541 mask
& WINED3DCOLORWRITEENABLE_BLUE
? GL_TRUE
: GL_FALSE
,
5542 mask
& WINED3DCOLORWRITEENABLE_ALPHA
? GL_TRUE
: GL_FALSE
);
5544 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5545 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5547 IWineD3DSurface_ModifyLocation(This
->lastActiveRenderTarget
, SFLAG_INDRAWABLE
, TRUE
);
5549 if (Flags
& WINED3DCLEAR_ZBUFFER
) {
5550 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5551 DWORD location
= This
->render_offscreen
? SFLAG_DS_OFFSCREEN
: SFLAG_DS_ONSCREEN
;
5552 surface_modify_ds_location(This
->stencilBufferTarget
, location
);
5557 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface
*)target
, &IID_IWineD3DSwapChain
, (void **)&swapchain
))) {
5558 if (target
== (IWineD3DSurfaceImpl
*) swapchain
->frontBuffer
) {
5561 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
5567 static HRESULT WINAPI
IWineD3DDeviceImpl_Clear(IWineD3DDevice
*iface
, DWORD Count
, CONST WINED3DRECT
* pRects
,
5568 DWORD Flags
, WINED3DCOLOR Color
, float Z
, DWORD Stencil
) {
5569 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5570 IWineD3DSurfaceImpl
*target
= (IWineD3DSurfaceImpl
*)This
->render_targets
[0];
5572 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This
,
5573 Count
, pRects
, Flags
, Color
, Z
, Stencil
);
5575 if(Flags
& (WINED3DCLEAR_ZBUFFER
| WINED3DCLEAR_STENCIL
) && This
->stencilBufferTarget
== NULL
) {
5576 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5577 /* TODO: What about depth stencil buffers without stencil bits? */
5578 return WINED3DERR_INVALIDCALL
;
5581 return IWineD3DDeviceImpl_ClearSurface(This
, target
, Count
, pRects
, Flags
, Color
, Z
, Stencil
);
5588 static void WINAPI
IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice
*iface
,
5589 WINED3DPRIMITIVETYPE primitive_type
)
5591 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5593 TRACE("iface %p, primitive_type %s\n", iface
, debug_d3dprimitivetype(primitive_type
));
5595 This
->updateStateBlock
->changed
.primitive_type
= TRUE
;
5596 This
->updateStateBlock
->gl_primitive_type
= gl_primitive_type_from_d3d(primitive_type
);
5599 static void WINAPI
IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice
*iface
,
5600 WINED3DPRIMITIVETYPE
*primitive_type
)
5602 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5604 TRACE("iface %p, primitive_type %p\n", iface
, primitive_type
);
5606 *primitive_type
= d3d_primitive_type_from_gl(This
->stateBlock
->gl_primitive_type
);
5608 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type
));
5611 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice
*iface
, UINT StartVertex
, UINT vertex_count
)
5613 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5615 TRACE("(%p) : start %u, count %u\n", This
, StartVertex
, vertex_count
);
5617 if(!This
->stateBlock
->vertexDecl
) {
5618 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
5619 return WINED3DERR_INVALIDCALL
;
5622 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5623 if(This
->stateBlock
->streamIsUP
) {
5624 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5625 This
->stateBlock
->streamIsUP
= FALSE
;
5628 if(This
->stateBlock
->loadBaseVertexIndex
!= 0) {
5629 This
->stateBlock
->loadBaseVertexIndex
= 0;
5630 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
5632 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5633 drawPrimitive(iface
, vertex_count
, 0/* NumVertices */, StartVertex
/* start_idx */,
5634 0 /* indxSize */, NULL
/* indxData */, 0 /* minIndex */);
5638 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice
*iface
,
5639 UINT minIndex
, UINT NumVertices
, UINT startIndex
, UINT index_count
)
5641 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5643 IWineD3DBuffer
*pIB
;
5646 pIB
= This
->stateBlock
->pIndexData
;
5648 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5649 * without an index buffer set. (The first time at least...)
5650 * D3D8 simply dies, but I doubt it can do much harm to return
5651 * D3DERR_INVALIDCALL there as well. */
5652 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This
);
5653 return WINED3DERR_INVALIDCALL
;
5656 if(!This
->stateBlock
->vertexDecl
) {
5657 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
5658 return WINED3DERR_INVALIDCALL
;
5661 if(This
->stateBlock
->streamIsUP
) {
5662 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5663 This
->stateBlock
->streamIsUP
= FALSE
;
5665 vbo
= ((struct wined3d_buffer
*) pIB
)->buffer_object
;
5667 TRACE("(%p) : min %u, vertex count %u, startIdx %u, index count %u\n",
5668 This
, minIndex
, NumVertices
, startIndex
, index_count
);
5670 if (This
->stateBlock
->IndexFmt
== WINED3DFMT_R16_UINT
) {
5676 if(This
->stateBlock
->loadBaseVertexIndex
!= This
->stateBlock
->baseVertexIndex
) {
5677 This
->stateBlock
->loadBaseVertexIndex
= This
->stateBlock
->baseVertexIndex
;
5678 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
5681 drawPrimitive(iface
, index_count
, NumVertices
, startIndex
, idxStride
,
5682 vbo
? NULL
: ((struct wined3d_buffer
*) pIB
)->resource
.allocatedMemory
, minIndex
);
5687 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice
*iface
, UINT vertex_count
,
5688 const void *pVertexStreamZeroData
, UINT VertexStreamZeroStride
)
5690 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5693 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
5694 This
, vertex_count
, pVertexStreamZeroData
, VertexStreamZeroStride
);
5696 if(!This
->stateBlock
->vertexDecl
) {
5697 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
5698 return WINED3DERR_INVALIDCALL
;
5701 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5702 vb
= This
->stateBlock
->streamSource
[0];
5703 This
->stateBlock
->streamSource
[0] = (IWineD3DBuffer
*)pVertexStreamZeroData
;
5704 if (vb
) IWineD3DBuffer_Release(vb
);
5705 This
->stateBlock
->streamOffset
[0] = 0;
5706 This
->stateBlock
->streamStride
[0] = VertexStreamZeroStride
;
5707 This
->stateBlock
->streamIsUP
= TRUE
;
5708 This
->stateBlock
->loadBaseVertexIndex
= 0;
5710 /* TODO: Only mark dirty if drawing from a different UP address */
5711 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_STREAMSRC
);
5713 drawPrimitive(iface
, vertex_count
, 0 /* NumVertices */, 0 /* start_idx */,
5714 0 /* indxSize*/, NULL
/* indxData */, 0 /* indxMin */);
5716 /* MSDN specifies stream zero settings must be set to NULL */
5717 This
->stateBlock
->streamStride
[0] = 0;
5718 This
->stateBlock
->streamSource
[0] = NULL
;
5720 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5721 * the new stream sources or use UP drawing again
5726 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice
*iface
, UINT MinVertexIndex
,
5727 UINT NumVertices
, UINT index_count
, const void *pIndexData
, WINED3DFORMAT IndexDataFormat
,
5728 const void *pVertexStreamZeroData
, UINT VertexStreamZeroStride
)
5731 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5735 TRACE("(%p) : MinVtxIdx %u, NumVIdx %u, index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u\n",
5736 This
, MinVertexIndex
, NumVertices
, index_count
, pIndexData
,
5737 IndexDataFormat
, pVertexStreamZeroData
, VertexStreamZeroStride
);
5739 if(!This
->stateBlock
->vertexDecl
) {
5740 WARN("(%p) : Called without a valid vertex declaration set\n", This
);
5741 return WINED3DERR_INVALIDCALL
;
5744 if (IndexDataFormat
== WINED3DFMT_R16_UINT
) {
5750 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5751 vb
= This
->stateBlock
->streamSource
[0];
5752 This
->stateBlock
->streamSource
[0] = (IWineD3DBuffer
*)pVertexStreamZeroData
;
5753 if (vb
) IWineD3DBuffer_Release(vb
);
5754 This
->stateBlock
->streamIsUP
= TRUE
;
5755 This
->stateBlock
->streamOffset
[0] = 0;
5756 This
->stateBlock
->streamStride
[0] = VertexStreamZeroStride
;
5758 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5759 This
->stateBlock
->baseVertexIndex
= 0;
5760 This
->stateBlock
->loadBaseVertexIndex
= 0;
5761 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5762 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
5763 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5765 drawPrimitive(iface
, index_count
, NumVertices
, 0 /* start_idx */,
5766 idxStride
, pIndexData
, MinVertexIndex
);
5768 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5769 This
->stateBlock
->streamSource
[0] = NULL
;
5770 This
->stateBlock
->streamStride
[0] = 0;
5771 ib
= This
->stateBlock
->pIndexData
;
5773 IWineD3DBuffer_Release(ib
);
5774 This
->stateBlock
->pIndexData
= NULL
;
5776 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5777 * SetStreamSource to specify a vertex buffer
5783 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice
*iface
,
5784 UINT vertex_count
, const WineDirect3DVertexStridedData
*DrawPrimStrideData
)
5786 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5788 /* Mark the state dirty until we have nicer tracking
5789 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5792 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
5793 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5794 This
->stateBlock
->baseVertexIndex
= 0;
5795 This
->up_strided
= DrawPrimStrideData
;
5796 drawPrimitive(iface
, vertex_count
, 0, 0, 0, NULL
, 0);
5797 This
->up_strided
= NULL
;
5801 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice
*iface
,
5802 UINT vertex_count
, const WineDirect3DVertexStridedData
*DrawPrimStrideData
,
5803 UINT NumVertices
, const void *pIndexData
, WINED3DFORMAT IndexDataFormat
)
5805 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5806 DWORD idxSize
= (IndexDataFormat
== WINED3DFMT_R32_UINT
? 4 : 2);
5808 /* Mark the state dirty until we have nicer tracking
5809 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5812 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VDECL
);
5813 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_INDEXBUFFER
);
5814 This
->stateBlock
->streamIsUP
= TRUE
;
5815 This
->stateBlock
->baseVertexIndex
= 0;
5816 This
->up_strided
= DrawPrimStrideData
;
5817 drawPrimitive(iface
, vertex_count
, 0 /* numindices */, 0 /* start_idx */, idxSize
, pIndexData
, 0 /* minindex */);
5818 This
->up_strided
= NULL
;
5822 static HRESULT
IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice
*iface
, IWineD3DVolume
*pSourceVolume
, IWineD3DVolume
*pDestinationVolume
) {
5823 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5824 * not callable by the app directly no parameter validation checks are needed here.
5826 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
5827 WINED3DLOCKED_BOX src
;
5828 WINED3DLOCKED_BOX dst
;
5830 TRACE("(%p)->(%p, %p)\n", This
, pSourceVolume
, pDestinationVolume
);
5832 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5833 * dirtification to improve loading performance.
5835 hr
= IWineD3DVolume_LockBox(pSourceVolume
, &src
, NULL
, WINED3DLOCK_READONLY
);
5836 if(FAILED(hr
)) return hr
;
5837 hr
= IWineD3DVolume_LockBox(pDestinationVolume
, &dst
, NULL
, WINED3DLOCK_DISCARD
);
5839 IWineD3DVolume_UnlockBox(pSourceVolume
);
5843 memcpy(dst
.pBits
, src
.pBits
, ((IWineD3DVolumeImpl
*) pDestinationVolume
)->resource
.size
);
5845 hr
= IWineD3DVolume_UnlockBox(pDestinationVolume
);
5847 IWineD3DVolume_UnlockBox(pSourceVolume
);
5849 hr
= IWineD3DVolume_UnlockBox(pSourceVolume
);
5854 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5855 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice
*iface
, IWineD3DBaseTexture
*pSourceTexture
, IWineD3DBaseTexture
*pDestinationTexture
){
5856 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5857 HRESULT hr
= WINED3D_OK
;
5858 WINED3DRESOURCETYPE sourceType
;
5859 WINED3DRESOURCETYPE destinationType
;
5862 /* TODO: think about moving the code into IWineD3DBaseTexture */
5864 TRACE("(%p) Source %p Destination %p\n", This
, pSourceTexture
, pDestinationTexture
);
5866 /* verify that the source and destination textures aren't NULL */
5867 if (NULL
== pSourceTexture
|| NULL
== pDestinationTexture
) {
5868 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5869 This
, pSourceTexture
, pDestinationTexture
);
5870 hr
= WINED3DERR_INVALIDCALL
;
5873 if (pSourceTexture
== pDestinationTexture
) {
5874 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5875 This
, pSourceTexture
, pDestinationTexture
);
5876 hr
= WINED3DERR_INVALIDCALL
;
5878 /* Verify that the source and destination textures are the same type */
5879 sourceType
= IWineD3DBaseTexture_GetType(pSourceTexture
);
5880 destinationType
= IWineD3DBaseTexture_GetType(pDestinationTexture
);
5882 if (sourceType
!= destinationType
) {
5883 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5885 hr
= WINED3DERR_INVALIDCALL
;
5888 /* check that both textures have the identical numbers of levels */
5889 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture
) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture
)) {
5890 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This
, pSourceTexture
, pDestinationTexture
);
5891 hr
= WINED3DERR_INVALIDCALL
;
5894 if (WINED3D_OK
== hr
) {
5895 IWineD3DBaseTextureImpl
*pDestImpl
= (IWineD3DBaseTextureImpl
*) pDestinationTexture
;
5897 /* Make sure that the destination texture is loaded */
5898 pDestImpl
->baseTexture
.internal_preload(pDestinationTexture
, SRGB_RGB
);
5900 /* Update every surface level of the texture */
5901 levels
= IWineD3DBaseTexture_GetLevelCount(pDestinationTexture
);
5903 switch (sourceType
) {
5904 case WINED3DRTYPE_TEXTURE
:
5906 IWineD3DSurface
*srcSurface
;
5907 IWineD3DSurface
*destSurface
;
5909 for (i
= 0 ; i
< levels
; ++i
) {
5910 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)pSourceTexture
, i
, &srcSurface
);
5911 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture
*)pDestinationTexture
, i
, &destSurface
);
5912 hr
= IWineD3DDevice_UpdateSurface(iface
, srcSurface
, NULL
, destSurface
, NULL
);
5913 IWineD3DSurface_Release(srcSurface
);
5914 IWineD3DSurface_Release(destSurface
);
5915 if (WINED3D_OK
!= hr
) {
5916 WARN("(%p) : Call to update surface failed\n", This
);
5922 case WINED3DRTYPE_CUBETEXTURE
:
5924 IWineD3DSurface
*srcSurface
;
5925 IWineD3DSurface
*destSurface
;
5926 WINED3DCUBEMAP_FACES faceType
;
5928 for (i
= 0 ; i
< levels
; ++i
) {
5929 /* Update each cube face */
5930 for (faceType
= WINED3DCUBEMAP_FACE_POSITIVE_X
; faceType
<= WINED3DCUBEMAP_FACE_NEGATIVE_Z
; ++faceType
){
5931 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)pSourceTexture
, faceType
, i
, &srcSurface
);
5932 if (WINED3D_OK
!= hr
) {
5933 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This
, faceType
, i
);
5935 TRACE("Got srcSurface %p\n", srcSurface
);
5937 hr
= IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture
*)pDestinationTexture
, faceType
, i
, &destSurface
);
5938 if (WINED3D_OK
!= hr
) {
5939 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This
, faceType
, i
);
5941 TRACE("Got desrSurface %p\n", destSurface
);
5943 hr
= IWineD3DDevice_UpdateSurface(iface
, srcSurface
, NULL
, destSurface
, NULL
);
5944 IWineD3DSurface_Release(srcSurface
);
5945 IWineD3DSurface_Release(destSurface
);
5946 if (WINED3D_OK
!= hr
) {
5947 WARN("(%p) : Call to update surface failed\n", This
);
5955 case WINED3DRTYPE_VOLUMETEXTURE
:
5957 IWineD3DVolume
*srcVolume
= NULL
;
5958 IWineD3DVolume
*destVolume
= NULL
;
5960 for (i
= 0 ; i
< levels
; ++i
) {
5961 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture
*)pSourceTexture
, i
, &srcVolume
);
5962 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture
*)pDestinationTexture
, i
, &destVolume
);
5963 hr
= IWineD3DDeviceImpl_UpdateVolume(iface
, srcVolume
, destVolume
);
5964 IWineD3DVolume_Release(srcVolume
);
5965 IWineD3DVolume_Release(destVolume
);
5966 if (WINED3D_OK
!= hr
) {
5967 WARN("(%p) : Call to update volume failed\n", This
);
5975 FIXME("(%p) : Unsupported source and destination type\n", This
);
5976 hr
= WINED3DERR_INVALIDCALL
;
5983 static HRESULT WINAPI
IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice
*iface
,UINT iSwapChain
, IWineD3DSurface
*pDestSurface
) {
5984 IWineD3DSwapChain
*swapChain
;
5986 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
5987 if(hr
== WINED3D_OK
) {
5988 hr
= IWineD3DSwapChain_GetFrontBufferData(swapChain
, pDestSurface
);
5989 IWineD3DSwapChain_Release(swapChain
);
5994 static HRESULT WINAPI
IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice
*iface
, DWORD
* pNumPasses
) {
5995 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
5996 IWineD3DBaseTextureImpl
*texture
;
5999 TRACE("(%p) : %p\n", This
, pNumPasses
);
6001 for(i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++) {
6002 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MINFILTER
] == WINED3DTEXF_NONE
) {
6003 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i
);
6004 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER
;
6006 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MAGFILTER
] == WINED3DTEXF_NONE
) {
6007 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i
);
6008 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER
;
6011 texture
= (IWineD3DBaseTextureImpl
*) This
->stateBlock
->textures
[i
];
6012 if (!texture
|| texture
->resource
.format_desc
->Flags
& WINED3DFMT_FLAG_FILTERING
) continue;
6014 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MAGFILTER
] != WINED3DTEXF_POINT
) {
6015 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i
);
6018 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MINFILTER
] != WINED3DTEXF_POINT
) {
6019 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i
);
6022 if(This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MIPFILTER
] != WINED3DTEXF_NONE
&&
6023 This
->stateBlock
->samplerState
[i
][WINED3DSAMP_MIPFILTER
] != WINED3DTEXF_POINT
/* sic! */) {
6024 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i
);
6029 /* return a sensible default */
6032 TRACE("returning D3D_OK\n");
6036 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl
*device
)
6040 for (i
= 0; i
< MAX_COMBINED_SAMPLERS
; i
++) {
6041 IWineD3DBaseTextureImpl
*texture
= (IWineD3DBaseTextureImpl
*)device
->stateBlock
->textures
[i
];
6042 if (texture
&& (texture
->resource
.format_desc
->format
== WINED3DFMT_P8
6043 || texture
->resource
.format_desc
->format
== WINED3DFMT_A8P8
))
6045 IWineD3DDeviceImpl_MarkStateDirty(device
, STATE_SAMPLER(i
));
6050 static HRESULT WINAPI
IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, CONST PALETTEENTRY
* pEntries
) {
6051 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6054 PALETTEENTRY
**palettes
;
6056 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
6058 if (PaletteNumber
>= MAX_PALETTES
) {
6059 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This
, PaletteNumber
, MAX_PALETTES
);
6060 return WINED3DERR_INVALIDCALL
;
6063 if (PaletteNumber
>= This
->NumberOfPalettes
) {
6064 NewSize
= This
->NumberOfPalettes
;
6067 } while(PaletteNumber
>= NewSize
);
6068 palettes
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, This
->palettes
, sizeof(PALETTEENTRY
*) * NewSize
);
6070 ERR("Out of memory!\n");
6071 return E_OUTOFMEMORY
;
6073 This
->palettes
= palettes
;
6074 This
->NumberOfPalettes
= NewSize
;
6077 if (!This
->palettes
[PaletteNumber
]) {
6078 This
->palettes
[PaletteNumber
] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY
) * 256);
6079 if (!This
->palettes
[PaletteNumber
]) {
6080 ERR("Out of memory!\n");
6081 return E_OUTOFMEMORY
;
6085 for (j
= 0; j
< 256; ++j
) {
6086 This
->palettes
[PaletteNumber
][j
].peRed
= pEntries
[j
].peRed
;
6087 This
->palettes
[PaletteNumber
][j
].peGreen
= pEntries
[j
].peGreen
;
6088 This
->palettes
[PaletteNumber
][j
].peBlue
= pEntries
[j
].peBlue
;
6089 This
->palettes
[PaletteNumber
][j
].peFlags
= pEntries
[j
].peFlags
;
6091 if (PaletteNumber
== This
->currentPalette
) dirtify_p8_texture_samplers(This
);
6092 TRACE("(%p) : returning\n", This
);
6096 static HRESULT WINAPI
IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice
*iface
, UINT PaletteNumber
, PALETTEENTRY
* pEntries
) {
6097 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6099 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
6100 if (PaletteNumber
>= This
->NumberOfPalettes
|| !This
->palettes
[PaletteNumber
]) {
6101 /* What happens in such situation isn't documented; Native seems to silently abort
6102 on such conditions. Return Invalid Call. */
6103 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This
, PaletteNumber
, This
->NumberOfPalettes
);
6104 return WINED3DERR_INVALIDCALL
;
6106 for (j
= 0; j
< 256; ++j
) {
6107 pEntries
[j
].peRed
= This
->palettes
[PaletteNumber
][j
].peRed
;
6108 pEntries
[j
].peGreen
= This
->palettes
[PaletteNumber
][j
].peGreen
;
6109 pEntries
[j
].peBlue
= This
->palettes
[PaletteNumber
][j
].peBlue
;
6110 pEntries
[j
].peFlags
= This
->palettes
[PaletteNumber
][j
].peFlags
;
6112 TRACE("(%p) : returning\n", This
);
6116 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT PaletteNumber
) {
6117 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6118 TRACE("(%p) : PaletteNumber %u\n", This
, PaletteNumber
);
6119 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
6120 (tested with reference rasterizer). Return Invalid Call. */
6121 if (PaletteNumber
>= This
->NumberOfPalettes
|| !This
->palettes
[PaletteNumber
]) {
6122 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This
, PaletteNumber
, This
->NumberOfPalettes
);
6123 return WINED3DERR_INVALIDCALL
;
6125 /*TODO: stateblocks */
6126 if (This
->currentPalette
!= PaletteNumber
) {
6127 This
->currentPalette
= PaletteNumber
;
6128 dirtify_p8_texture_samplers(This
);
6130 TRACE("(%p) : returning\n", This
);
6134 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice
*iface
, UINT
* PaletteNumber
) {
6135 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6136 if (PaletteNumber
== NULL
) {
6137 WARN("(%p) : returning Invalid Call\n", This
);
6138 return WINED3DERR_INVALIDCALL
;
6140 /*TODO: stateblocks */
6141 *PaletteNumber
= This
->currentPalette
;
6142 TRACE("(%p) : returning %u\n", This
, *PaletteNumber
);
6146 static HRESULT WINAPI
IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice
*iface
, BOOL bSoftware
) {
6147 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6151 FIXME("(%p) : stub\n", This
);
6155 This
->softwareVertexProcessing
= bSoftware
;
6160 static BOOL WINAPI
IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice
*iface
) {
6161 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6165 FIXME("(%p) : stub\n", This
);
6168 return This
->softwareVertexProcessing
;
6172 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DRASTER_STATUS
* pRasterStatus
) {
6173 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6174 IWineD3DSwapChain
*swapChain
;
6177 TRACE("(%p) : SwapChain %d returning %p\n", This
, iSwapChain
, pRasterStatus
);
6179 hr
= IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapChain
);
6180 if(hr
== WINED3D_OK
){
6181 hr
= IWineD3DSwapChain_GetRasterStatus(swapChain
, pRasterStatus
);
6182 IWineD3DSwapChain_Release(swapChain
);
6184 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This
);
6190 static HRESULT WINAPI
IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice
*iface
, float nSegments
) {
6191 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6193 if(nSegments
!= 0.0f
) {
6196 FIXME("(%p) : stub nSegments(%f)\n", This
, nSegments
);
6203 static float WINAPI
IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice
*iface
) {
6204 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6208 FIXME("(%p) : stub returning(%f)\n", This
, 0.0f
);
6214 static HRESULT WINAPI
IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice
*iface
, IWineD3DSurface
*pSourceSurface
, CONST RECT
* pSourceRect
, IWineD3DSurface
*pDestinationSurface
, CONST POINT
* pDestPoint
) {
6215 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6216 /** TODO: remove casts to IWineD3DSurfaceImpl
6217 * NOTE: move code to surface to accomplish this
6218 ****************************************/
6219 IWineD3DSurfaceImpl
*pSrcSurface
= (IWineD3DSurfaceImpl
*)pSourceSurface
;
6220 int srcWidth
, srcHeight
;
6221 unsigned int srcSurfaceWidth
, srcSurfaceHeight
, destSurfaceWidth
, destSurfaceHeight
;
6222 WINED3DFORMAT destFormat
, srcFormat
;
6224 int srcLeft
, destLeft
, destTop
;
6225 WINED3DPOOL srcPool
, destPool
;
6227 int rowoffset
= 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
6228 glDescriptor
*glDescription
= NULL
;
6229 const struct GlPixelFormatDesc
*src_format_desc
, *dst_format_desc
;
6233 CONVERT_TYPES convert
= NO_CONVERSION
;
6235 WINED3DSURFACE_DESC winedesc
;
6237 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This
, pSourceSurface
, pSourceRect
, pDestinationSurface
, pDestPoint
);
6238 memset(&winedesc
, 0, sizeof(winedesc
));
6239 winedesc
.Width
= &srcSurfaceWidth
;
6240 winedesc
.Height
= &srcSurfaceHeight
;
6241 winedesc
.Pool
= &srcPool
;
6242 winedesc
.Format
= &srcFormat
;
6244 IWineD3DSurface_GetDesc(pSourceSurface
, &winedesc
);
6246 winedesc
.Width
= &destSurfaceWidth
;
6247 winedesc
.Height
= &destSurfaceHeight
;
6248 winedesc
.Pool
= &destPool
;
6249 winedesc
.Format
= &destFormat
;
6250 winedesc
.Size
= &destSize
;
6252 IWineD3DSurface_GetDesc(pDestinationSurface
, &winedesc
);
6254 if(srcPool
!= WINED3DPOOL_SYSTEMMEM
|| destPool
!= WINED3DPOOL_DEFAULT
){
6255 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface
, pDestinationSurface
);
6256 return WINED3DERR_INVALIDCALL
;
6259 /* This call loads the opengl surface directly, instead of copying the surface to the
6260 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
6261 * copy in sysmem and use regular surface loading.
6263 d3dfmt_get_conv((IWineD3DSurfaceImpl
*) pDestinationSurface
, FALSE
, TRUE
,
6264 &dummy
, &dummy
, &dummy
, &convert
, &bpp
, FALSE
);
6265 if(convert
!= NO_CONVERSION
) {
6266 return IWineD3DSurface_BltFast(pDestinationSurface
,
6267 pDestPoint
? pDestPoint
->x
: 0,
6268 pDestPoint
? pDestPoint
->y
: 0,
6269 pSourceSurface
, pSourceRect
, 0);
6272 if (destFormat
== WINED3DFMT_UNKNOWN
) {
6273 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This
);
6274 IWineD3DSurface_SetFormat(pDestinationSurface
, srcFormat
);
6276 /* Get the update surface description */
6277 IWineD3DSurface_GetDesc(pDestinationSurface
, &winedesc
);
6280 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
6283 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
6284 checkGLcall("glActiveTextureARB");
6287 /* Make sure the surface is loaded and up to date */
6288 surface_internal_preload(pDestinationSurface
, SRGB_RGB
);
6289 IWineD3DSurface_BindTexture(pDestinationSurface
, FALSE
);
6291 IWineD3DSurface_GetGlDesc(pDestinationSurface
, &glDescription
);
6293 src_format_desc
= ((IWineD3DSurfaceImpl
*)pSrcSurface
)->resource
.format_desc
;
6294 dst_format_desc
= ((IWineD3DSurfaceImpl
*)pDestinationSurface
)->resource
.format_desc
;
6296 /* this needs to be done in lines if the sourceRect != the sourceWidth */
6297 srcWidth
= pSourceRect
? pSourceRect
->right
- pSourceRect
->left
: srcSurfaceWidth
;
6298 srcHeight
= pSourceRect
? pSourceRect
->bottom
- pSourceRect
->top
: srcSurfaceHeight
;
6299 srcLeft
= pSourceRect
? pSourceRect
->left
: 0;
6300 destLeft
= pDestPoint
? pDestPoint
->x
: 0;
6301 destTop
= pDestPoint
? pDestPoint
->y
: 0;
6304 /* This function doesn't support compressed textures
6305 the pitch is just bytesPerPixel * width */
6306 if(srcWidth
!= srcSurfaceWidth
|| srcLeft
){
6307 rowoffset
= srcSurfaceWidth
* src_format_desc
->byte_count
;
6308 offset
+= srcLeft
* src_format_desc
->byte_count
;
6309 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
6311 /* TODO DXT formats */
6313 if(pSourceRect
!= NULL
&& pSourceRect
->top
!= 0){
6314 offset
+= pSourceRect
->top
* srcSurfaceWidth
* src_format_desc
->byte_count
;
6316 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
6317 This
, glDescription
->level
, destLeft
, destTop
, srcWidth
, srcHeight
, dst_format_desc
->glFormat
,
6318 dst_format_desc
->glType
, IWineD3DSurface_GetData(pSourceSurface
), offset
);
6321 if (IWineD3DSurface_GetData(pSourceSurface
) == NULL
) {
6323 /* need to lock the surface to get the data */
6324 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
6329 /* TODO: Cube and volume support */
6331 /* not a whole row so we have to do it a line at a time */
6334 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
6335 const unsigned char* data
=((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface
)) + offset
;
6337 for (j
= destTop
; j
< (srcHeight
+ destTop
); ++j
)
6339 glTexSubImage2D(glDescription
->target
, glDescription
->level
, destLeft
, j
,
6340 srcWidth
, 1, dst_format_desc
->glFormat
, dst_format_desc
->glType
,data
);
6344 } else { /* Full width, so just write out the whole texture */
6345 const unsigned char* data
= ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface
)) + offset
;
6347 if (WINED3DFMT_DXT1
== destFormat
||
6348 WINED3DFMT_DXT2
== destFormat
||
6349 WINED3DFMT_DXT3
== destFormat
||
6350 WINED3DFMT_DXT4
== destFormat
||
6351 WINED3DFMT_DXT5
== destFormat
) {
6352 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC
)) {
6353 if (destSurfaceHeight
!= srcHeight
|| destSurfaceWidth
!= srcWidth
) {
6354 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
6355 FIXME("Updating part of a compressed texture is not supported at the moment\n");
6356 } if (destFormat
!= srcFormat
) {
6357 FIXME("Updating mixed format compressed texture is not curretly support\n");
6359 GL_EXTCALL(glCompressedTexImage2DARB(glDescription
->target
, glDescription
->level
,
6360 dst_format_desc
->glInternal
, srcWidth
, srcHeight
, 0, destSize
, data
));
6363 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
6368 glTexSubImage2D(glDescription
->target
, glDescription
->level
, destLeft
, destTop
,
6369 srcWidth
, srcHeight
, dst_format_desc
->glFormat
, dst_format_desc
->glType
, data
);
6372 checkGLcall("glTexSubImage2D");
6376 IWineD3DSurface_ModifyLocation(pDestinationSurface
, SFLAG_INTEXTURE
, TRUE
);
6377 sampler
= This
->rev_tex_unit_map
[0];
6378 if (sampler
!= -1) {
6379 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(sampler
));
6385 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice
*iface
, UINT Handle
, CONST
float* pNumSegs
, CONST WINED3DRECTPATCH_INFO
* pRectPatchInfo
) {
6386 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6387 struct WineD3DRectPatch
*patch
;
6388 GLenum old_primitive_type
;
6392 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This
, Handle
, pNumSegs
, pRectPatchInfo
);
6394 if(!(Handle
|| pRectPatchInfo
)) {
6395 /* TODO: Write a test for the return value, thus the FIXME */
6396 FIXME("Both Handle and pRectPatchInfo are NULL\n");
6397 return WINED3DERR_INVALIDCALL
;
6401 i
= PATCHMAP_HASHFUNC(Handle
);
6403 LIST_FOR_EACH(e
, &This
->patches
[i
]) {
6404 patch
= LIST_ENTRY(e
, struct WineD3DRectPatch
, entry
);
6405 if(patch
->Handle
== Handle
) {
6412 TRACE("Patch does not exist. Creating a new one\n");
6413 patch
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*patch
));
6414 patch
->Handle
= Handle
;
6415 list_add_head(&This
->patches
[i
], &patch
->entry
);
6417 TRACE("Found existing patch %p\n", patch
);
6420 /* Since opengl does not load tesselated vertex attributes into numbered vertex
6421 * attributes we have to tesselate, read back, and draw. This needs a patch
6422 * management structure instance. Create one.
6424 * A possible improvement is to check if a vertex shader is used, and if not directly
6427 FIXME("Drawing an uncached patch. This is slow\n");
6428 patch
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*patch
));
6431 if(pNumSegs
[0] != patch
->numSegs
[0] || pNumSegs
[1] != patch
->numSegs
[1] ||
6432 pNumSegs
[2] != patch
->numSegs
[2] || pNumSegs
[3] != patch
->numSegs
[3] ||
6433 (pRectPatchInfo
&& memcmp(pRectPatchInfo
, &patch
->RectPatchInfo
, sizeof(*pRectPatchInfo
)) != 0) ) {
6435 TRACE("Tesselation density or patch info changed, retesselating\n");
6437 if(pRectPatchInfo
) {
6438 patch
->RectPatchInfo
= *pRectPatchInfo
;
6440 patch
->numSegs
[0] = pNumSegs
[0];
6441 patch
->numSegs
[1] = pNumSegs
[1];
6442 patch
->numSegs
[2] = pNumSegs
[2];
6443 patch
->numSegs
[3] = pNumSegs
[3];
6445 hr
= tesselate_rectpatch(This
, patch
);
6447 WARN("Patch tesselation failed\n");
6449 /* Do not release the handle to store the params of the patch */
6451 HeapFree(GetProcessHeap(), 0, patch
);
6457 This
->currentPatch
= patch
;
6458 old_primitive_type
= This
->stateBlock
->gl_primitive_type
;
6459 This
->stateBlock
->gl_primitive_type
= GL_TRIANGLES
;
6460 IWineD3DDevice_DrawPrimitiveStrided(iface
, patch
->numSegs
[0] * patch
->numSegs
[1] * 2 * 3, &patch
->strided
);
6461 This
->stateBlock
->gl_primitive_type
= old_primitive_type
;
6462 This
->currentPatch
= NULL
;
6464 /* Destroy uncached patches */
6466 HeapFree(GetProcessHeap(), 0, patch
->mem
);
6467 HeapFree(GetProcessHeap(), 0, patch
);
6472 static HRESULT WINAPI
IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice
*iface
, UINT Handle
, CONST
float* pNumSegs
, CONST WINED3DTRIPATCH_INFO
* pTriPatchInfo
) {
6473 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6474 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This
, Handle
, pNumSegs
, pTriPatchInfo
);
6475 FIXME("(%p) : Stub\n", This
);
6479 static HRESULT WINAPI
IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice
*iface
, UINT Handle
) {
6480 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6482 struct WineD3DRectPatch
*patch
;
6484 TRACE("(%p) Handle(%d)\n", This
, Handle
);
6486 i
= PATCHMAP_HASHFUNC(Handle
);
6487 LIST_FOR_EACH(e
, &This
->patches
[i
]) {
6488 patch
= LIST_ENTRY(e
, struct WineD3DRectPatch
, entry
);
6489 if(patch
->Handle
== Handle
) {
6490 TRACE("Deleting patch %p\n", patch
);
6491 list_remove(&patch
->entry
);
6492 HeapFree(GetProcessHeap(), 0, patch
->mem
);
6493 HeapFree(GetProcessHeap(), 0, patch
);
6498 /* TODO: Write a test for the return value */
6499 FIXME("Attempt to destroy nonexistent patch\n");
6500 return WINED3DERR_INVALIDCALL
;
6503 static IWineD3DSwapChain
*get_swapchain(IWineD3DSurface
*target
) {
6505 IWineD3DSwapChain
*swapchain
;
6507 hr
= IWineD3DSurface_GetContainer(target
, &IID_IWineD3DSwapChain
, (void **)&swapchain
);
6508 if (SUCCEEDED(hr
)) {
6509 IWineD3DSwapChain_Release((IUnknown
*)swapchain
);
6516 static void color_fill_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*surface
,
6517 const WINED3DRECT
*rect
, const float color
[4])
6519 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6520 IWineD3DSwapChain
*swapchain
;
6522 swapchain
= get_swapchain(surface
);
6526 TRACE("Surface %p is onscreen\n", surface
);
6528 ActivateContext(This
, surface
, CTXUSAGE_RESOURCELOAD
);
6530 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
6531 buffer
= surface_get_gl_buffer(surface
, swapchain
);
6532 glDrawBuffer(buffer
);
6533 checkGLcall("glDrawBuffer()");
6535 TRACE("Surface %p is offscreen\n", surface
);
6537 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
6539 context_bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->activeContext
->dst_fbo
);
6540 context_attach_surface_fbo(This
, GL_FRAMEBUFFER_EXT
, 0, surface
);
6541 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, GL_RENDERBUFFER_EXT
, 0));
6542 checkGLcall("glFramebufferRenderbufferEXT");
6546 glEnable(GL_SCISSOR_TEST
);
6548 glScissor(rect
->x1
, rect
->y1
, rect
->x2
- rect
->x1
, rect
->y2
- rect
->y1
);
6550 glScissor(rect
->x1
, ((IWineD3DSurfaceImpl
*)surface
)->currentDesc
.Height
- rect
->y2
,
6551 rect
->x2
- rect
->x1
, rect
->y2
- rect
->y1
);
6553 checkGLcall("glScissor");
6554 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SCISSORRECT
);
6556 glDisable(GL_SCISSOR_TEST
);
6558 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE
));
6560 glDisable(GL_BLEND
);
6561 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE
));
6563 glColorMask(GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
6564 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_COLORWRITEENABLE
));
6566 glClearColor(color
[0], color
[1], color
[2], color
[3]);
6567 glClear(GL_COLOR_BUFFER_BIT
);
6568 checkGLcall("glClear");
6570 if (This
->activeContext
->current_fbo
) {
6571 context_bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->activeContext
->current_fbo
->id
);
6573 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
6574 checkGLcall("glBindFramebuffer()");
6577 if (swapchain
&& surface
== ((IWineD3DSwapChainImpl
*)swapchain
)->frontBuffer
6578 && ((IWineD3DSwapChainImpl
*)swapchain
)->backBuffer
) {
6579 glDrawBuffer(GL_BACK
);
6580 checkGLcall("glDrawBuffer()");
6586 static inline DWORD
argb_to_fmt(DWORD color
, WINED3DFORMAT destfmt
) {
6587 unsigned int r
, g
, b
, a
;
6590 if(destfmt
== WINED3DFMT_A8R8G8B8
|| destfmt
== WINED3DFMT_X8R8G8B8
||
6591 destfmt
== WINED3DFMT_R8G8B8
)
6594 TRACE("Converting color %08x to format %s\n", color
, debug_d3dformat(destfmt
));
6596 a
= (color
& 0xff000000) >> 24;
6597 r
= (color
& 0x00ff0000) >> 16;
6598 g
= (color
& 0x0000ff00) >> 8;
6599 b
= (color
& 0x000000ff) >> 0;
6603 case WINED3DFMT_R5G6B5
:
6604 if(r
== 0xff && g
== 0xff && b
== 0xff) return 0xffff;
6611 TRACE("Returning %08x\n", ret
);
6614 case WINED3DFMT_X1R5G5B5
:
6615 case WINED3DFMT_A1R5G5B5
:
6624 TRACE("Returning %08x\n", ret
);
6627 case WINED3DFMT_A8_UNORM
:
6628 TRACE("Returning %08x\n", a
);
6631 case WINED3DFMT_X4R4G4B4
:
6632 case WINED3DFMT_A4R4G4B4
:
6641 TRACE("Returning %08x\n", ret
);
6644 case WINED3DFMT_R3G3B2
:
6651 TRACE("Returning %08x\n", ret
);
6654 case WINED3DFMT_X8B8G8R8
:
6655 case WINED3DFMT_R8G8B8A8_UNORM
:
6660 TRACE("Returning %08x\n", ret
);
6663 case WINED3DFMT_A2R10G10B10
:
6665 r
= (r
* 1024) / 256;
6666 g
= (g
* 1024) / 256;
6667 b
= (b
* 1024) / 256;
6672 TRACE("Returning %08x\n", ret
);
6675 case WINED3DFMT_R10G10B10A2_UNORM
:
6677 r
= (r
* 1024) / 256;
6678 g
= (g
* 1024) / 256;
6679 b
= (b
* 1024) / 256;
6684 TRACE("Returning %08x\n", ret
);
6688 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt
));
6693 static HRESULT WINAPI
IWineD3DDeviceImpl_ColorFill(IWineD3DDevice
*iface
, IWineD3DSurface
*pSurface
, CONST WINED3DRECT
* pRect
, WINED3DCOLOR color
) {
6694 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
6695 IWineD3DSurfaceImpl
*surface
= (IWineD3DSurfaceImpl
*) pSurface
;
6697 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This
, pSurface
, pRect
, color
);
6699 if (surface
->resource
.pool
!= WINED3DPOOL_DEFAULT
&& surface
->resource
.pool
!= WINED3DPOOL_SYSTEMMEM
) {
6700 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6701 return WINED3DERR_INVALIDCALL
;
6704 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
6705 const float c
[4] = {D3DCOLOR_R(color
), D3DCOLOR_G(color
), D3DCOLOR_B(color
), D3DCOLOR_A(color
)};
6706 color_fill_fbo(iface
, pSurface
, pRect
, c
);
6709 /* Just forward this to the DirectDraw blitting engine */
6710 memset(&BltFx
, 0, sizeof(BltFx
));
6711 BltFx
.dwSize
= sizeof(BltFx
);
6712 BltFx
.u5
.dwFillColor
= argb_to_fmt(color
, surface
->resource
.format_desc
->format
);
6713 return IWineD3DSurface_Blt(pSurface
, (const RECT
*)pRect
, NULL
, NULL
,
6714 WINEDDBLT_COLORFILL
, &BltFx
, WINED3DTEXF_NONE
);
6718 static void WINAPI
IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice
*iface
,
6719 IWineD3DRendertargetView
*rendertarget_view
, const float color
[4])
6721 IWineD3DResource
*resource
;
6722 IWineD3DSurface
*surface
;
6725 hr
= IWineD3DRendertargetView_GetResource(rendertarget_view
, &resource
);
6728 ERR("Failed to get resource, hr %#x\n", hr
);
6732 if (IWineD3DResource_GetType(resource
) != WINED3DRTYPE_SURFACE
)
6734 FIXME("Only supported on surface resources\n");
6735 IWineD3DResource_Release(resource
);
6739 surface
= (IWineD3DSurface
*)resource
;
6741 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
)
6743 color_fill_fbo(iface
, surface
, NULL
, color
);
6750 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
6752 c
= ((DWORD
)(color
[2] * 255.0));
6753 c
|= ((DWORD
)(color
[1] * 255.0)) << 8;
6754 c
|= ((DWORD
)(color
[0] * 255.0)) << 16;
6755 c
|= ((DWORD
)(color
[3] * 255.0)) << 24;
6757 /* Just forward this to the DirectDraw blitting engine */
6758 memset(&BltFx
, 0, sizeof(BltFx
));
6759 BltFx
.dwSize
= sizeof(BltFx
);
6760 BltFx
.u5
.dwFillColor
= argb_to_fmt(c
, ((IWineD3DSurfaceImpl
*)surface
)->resource
.format_desc
->format
);
6761 hr
= IWineD3DSurface_Blt(surface
, NULL
, NULL
, NULL
, WINEDDBLT_COLORFILL
, &BltFx
, WINED3DTEXF_NONE
);
6764 ERR("Blt failed, hr %#x\n", hr
);
6768 IWineD3DResource_Release(resource
);
6771 /* rendertarget and depth stencil functions */
6772 static HRESULT WINAPI
IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice
* iface
,DWORD RenderTargetIndex
, IWineD3DSurface
**ppRenderTarget
) {
6773 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6775 if (RenderTargetIndex
>= GL_LIMITS(buffers
)) {
6776 ERR("(%p) : Only %d render targets are supported.\n", This
, GL_LIMITS(buffers
));
6777 return WINED3DERR_INVALIDCALL
;
6780 *ppRenderTarget
= This
->render_targets
[RenderTargetIndex
];
6781 TRACE("(%p) : RenderTarget %d Index returning %p\n", This
, RenderTargetIndex
, *ppRenderTarget
);
6782 /* Note inc ref on returned surface */
6783 if(*ppRenderTarget
!= NULL
)
6784 IWineD3DSurface_AddRef(*ppRenderTarget
);
6788 static HRESULT WINAPI
IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice
*iface
, IWineD3DSurface
*Front
, IWineD3DSurface
*Back
) {
6789 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6790 IWineD3DSurfaceImpl
*FrontImpl
= (IWineD3DSurfaceImpl
*) Front
;
6791 IWineD3DSurfaceImpl
*BackImpl
= (IWineD3DSurfaceImpl
*) Back
;
6792 IWineD3DSwapChainImpl
*Swapchain
;
6795 TRACE("(%p)->(%p,%p)\n", This
, FrontImpl
, BackImpl
);
6797 hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**) &Swapchain
);
6798 if(hr
!= WINED3D_OK
) {
6799 ERR("Can't get the swapchain\n");
6803 /* Make sure to release the swapchain */
6804 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) Swapchain
);
6806 if(FrontImpl
&& !(FrontImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) ) {
6807 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6808 return WINED3DERR_INVALIDCALL
;
6810 else if(BackImpl
&& !(BackImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)) {
6811 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6812 return WINED3DERR_INVALIDCALL
;
6815 if(Swapchain
->frontBuffer
!= Front
) {
6816 TRACE("Changing the front buffer from %p to %p\n", Swapchain
->frontBuffer
, Front
);
6818 if(Swapchain
->frontBuffer
)
6820 IWineD3DSurface_SetContainer(Swapchain
->frontBuffer
, NULL
);
6821 ((IWineD3DSurfaceImpl
*)Swapchain
->frontBuffer
)->Flags
&= ~SFLAG_SWAPCHAIN
;
6823 Swapchain
->frontBuffer
= Front
;
6825 if(Swapchain
->frontBuffer
) {
6826 IWineD3DSurface_SetContainer(Swapchain
->frontBuffer
, (IWineD3DBase
*) Swapchain
);
6827 ((IWineD3DSurfaceImpl
*)Swapchain
->frontBuffer
)->Flags
|= SFLAG_SWAPCHAIN
;
6831 if(Back
&& !Swapchain
->backBuffer
) {
6832 /* We need memory for the back buffer array - only one back buffer this way */
6833 Swapchain
->backBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IWineD3DSurface
*));
6834 if(!Swapchain
->backBuffer
) {
6835 ERR("Out of memory\n");
6836 return E_OUTOFMEMORY
;
6840 if(Swapchain
->backBuffer
[0] != Back
) {
6841 TRACE("Changing the back buffer from %p to %p\n", Swapchain
->backBuffer
, Back
);
6843 /* What to do about the context here in the case of multithreading? Not sure.
6844 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6847 if(!Swapchain
->backBuffer
[0]) {
6848 /* GL was told to draw to the front buffer at creation,
6851 glDrawBuffer(GL_BACK
);
6852 checkGLcall("glDrawBuffer(GL_BACK)");
6853 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6854 Swapchain
->presentParms
.BackBufferCount
= 1;
6856 /* That makes problems - disable for now */
6857 /* glDrawBuffer(GL_FRONT); */
6858 checkGLcall("glDrawBuffer(GL_FRONT)");
6859 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6860 Swapchain
->presentParms
.BackBufferCount
= 0;
6864 if(Swapchain
->backBuffer
[0])
6866 IWineD3DSurface_SetContainer(Swapchain
->backBuffer
[0], NULL
);
6867 ((IWineD3DSurfaceImpl
*)Swapchain
->backBuffer
[0])->Flags
&= ~SFLAG_SWAPCHAIN
;
6869 Swapchain
->backBuffer
[0] = Back
;
6871 if(Swapchain
->backBuffer
[0]) {
6872 IWineD3DSurface_SetContainer(Swapchain
->backBuffer
[0], (IWineD3DBase
*) Swapchain
);
6873 ((IWineD3DSurfaceImpl
*)Swapchain
->backBuffer
[0])->Flags
|= SFLAG_SWAPCHAIN
;
6875 HeapFree(GetProcessHeap(), 0, Swapchain
->backBuffer
);
6876 Swapchain
->backBuffer
= NULL
;
6884 static HRESULT WINAPI
IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice
* iface
, IWineD3DSurface
**ppZStencilSurface
) {
6885 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6886 *ppZStencilSurface
= This
->stencilBufferTarget
;
6887 TRACE("(%p) : zStencilSurface returning %p\n", This
, *ppZStencilSurface
);
6889 if(*ppZStencilSurface
!= NULL
) {
6890 /* Note inc ref on returned surface */
6891 IWineD3DSurface_AddRef(*ppZStencilSurface
);
6894 return WINED3DERR_NOTFOUND
;
6898 void stretch_rect_fbo(IWineD3DDevice
*iface
, IWineD3DSurface
*src_surface
, WINED3DRECT
*src_rect
,
6899 IWineD3DSurface
*dst_surface
, WINED3DRECT
*dst_rect
, const WINED3DTEXTUREFILTERTYPE filter
, BOOL flip
)
6901 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
6902 GLbitfield mask
= GL_COLOR_BUFFER_BIT
; /* TODO: Support blitting depth/stencil surfaces */
6903 IWineD3DSwapChain
*src_swapchain
, *dst_swapchain
;
6905 POINT offset
= {0, 0};
6907 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6908 This
, src_surface
, src_rect
, dst_surface
, dst_rect
, debug_d3dtexturefiltertype(filter
), filter
, flip
);
6909 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
);
6910 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect
->x1
, dst_rect
->y1
, dst_rect
->x2
, dst_rect
->y2
);
6913 case WINED3DTEXF_LINEAR
:
6914 gl_filter
= GL_LINEAR
;
6918 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter
), filter
);
6919 case WINED3DTEXF_NONE
:
6920 case WINED3DTEXF_POINT
:
6921 gl_filter
= GL_NEAREST
;
6925 /* Attach src surface to src fbo */
6926 src_swapchain
= get_swapchain(src_surface
);
6927 if (src_swapchain
) {
6928 GLenum buffer
= surface_get_gl_buffer(src_surface
, src_swapchain
);
6930 TRACE("Source surface %p is onscreen\n", src_surface
);
6931 ActivateContext(This
, src_surface
, CTXUSAGE_RESOURCELOAD
);
6932 /* Make sure the drawable is up to date. In the offscreen case
6933 * attach_surface_fbo() implicitly takes care of this. */
6934 IWineD3DSurface_LoadLocation(src_surface
, SFLAG_INDRAWABLE
, NULL
);
6936 if(buffer
== GL_FRONT
) {
6939 ClientToScreen(((IWineD3DSwapChainImpl
*)src_swapchain
)->win_handle
, &offset
);
6940 GetClientRect(((IWineD3DSwapChainImpl
*)src_swapchain
)->win_handle
, &windowsize
);
6941 h
= windowsize
.bottom
- windowsize
.top
;
6942 src_rect
->x1
-= offset
.x
; src_rect
->x2
-=offset
.x
;
6943 src_rect
->y1
= offset
.y
+ h
- src_rect
->y1
;
6944 src_rect
->y2
= offset
.y
+ h
- src_rect
->y2
;
6946 src_rect
->y1
= ((IWineD3DSurfaceImpl
*)src_surface
)->currentDesc
.Height
- src_rect
->y1
;
6947 src_rect
->y2
= ((IWineD3DSurfaceImpl
*)src_surface
)->currentDesc
.Height
- src_rect
->y2
;
6951 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT
, 0));
6952 glReadBuffer(buffer
);
6953 checkGLcall("glReadBuffer()");
6955 TRACE("Source surface %p is offscreen\n", src_surface
);
6957 context_bind_fbo(iface
, GL_READ_FRAMEBUFFER_EXT
, &This
->activeContext
->src_fbo
);
6958 context_attach_surface_fbo(This
, GL_READ_FRAMEBUFFER_EXT
, 0, src_surface
);
6959 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT
);
6960 checkGLcall("glReadBuffer()");
6961 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, GL_RENDERBUFFER_EXT
, 0));
6962 checkGLcall("glFramebufferRenderbufferEXT");
6966 /* Attach dst surface to dst fbo */
6967 dst_swapchain
= get_swapchain(dst_surface
);
6968 if (dst_swapchain
) {
6969 GLenum buffer
= surface_get_gl_buffer(dst_surface
, dst_swapchain
);
6971 TRACE("Destination surface %p is onscreen\n", dst_surface
);
6972 ActivateContext(This
, dst_surface
, CTXUSAGE_RESOURCELOAD
);
6973 /* Make sure the drawable is up to date. In the offscreen case
6974 * attach_surface_fbo() implicitly takes care of this. */
6975 IWineD3DSurface_LoadLocation(dst_surface
, SFLAG_INDRAWABLE
, NULL
);
6977 if(buffer
== GL_FRONT
) {
6980 ClientToScreen(((IWineD3DSwapChainImpl
*)dst_swapchain
)->win_handle
, &offset
);
6981 GetClientRect(((IWineD3DSwapChainImpl
*)dst_swapchain
)->win_handle
, &windowsize
);
6982 h
= windowsize
.bottom
- windowsize
.top
;
6983 dst_rect
->x1
-= offset
.x
; dst_rect
->x2
-=offset
.x
;
6984 dst_rect
->y1
= offset
.y
+ h
- dst_rect
->y1
;
6985 dst_rect
->y2
= offset
.y
+ h
- dst_rect
->y2
;
6987 /* Screen coords = window coords, surface height = window height */
6988 dst_rect
->y1
= ((IWineD3DSurfaceImpl
*)dst_surface
)->currentDesc
.Height
- dst_rect
->y1
;
6989 dst_rect
->y2
= ((IWineD3DSurfaceImpl
*)dst_surface
)->currentDesc
.Height
- dst_rect
->y2
;
6993 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT
, 0));
6994 glDrawBuffer(buffer
);
6995 checkGLcall("glDrawBuffer()");
6997 TRACE("Destination surface %p is offscreen\n", dst_surface
);
6999 /* No src or dst swapchain? Make sure some context is active(multithreading) */
7000 if(!src_swapchain
) {
7001 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
7005 context_bind_fbo(iface
, GL_DRAW_FRAMEBUFFER_EXT
, &This
->activeContext
->dst_fbo
);
7006 context_attach_surface_fbo(This
, GL_DRAW_FRAMEBUFFER_EXT
, 0, dst_surface
);
7007 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT
);
7008 checkGLcall("glDrawBuffer()");
7009 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT
, GL_DEPTH_ATTACHMENT_EXT
, GL_RENDERBUFFER_EXT
, 0));
7010 checkGLcall("glFramebufferRenderbufferEXT");
7012 glDisable(GL_SCISSOR_TEST
);
7013 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE
));
7016 GL_EXTCALL(glBlitFramebufferEXT(src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
,
7017 dst_rect
->x1
, dst_rect
->y2
, dst_rect
->x2
, dst_rect
->y1
, mask
, gl_filter
));
7018 checkGLcall("glBlitFramebuffer()");
7020 GL_EXTCALL(glBlitFramebufferEXT(src_rect
->x1
, src_rect
->y1
, src_rect
->x2
, src_rect
->y2
,
7021 dst_rect
->x1
, dst_rect
->y1
, dst_rect
->x2
, dst_rect
->y2
, mask
, gl_filter
));
7022 checkGLcall("glBlitFramebuffer()");
7025 IWineD3DSurface_ModifyLocation(dst_surface
, SFLAG_INDRAWABLE
, TRUE
);
7027 if (This
->activeContext
->current_fbo
) {
7028 context_bind_fbo(iface
, GL_FRAMEBUFFER_EXT
, &This
->activeContext
->current_fbo
->id
);
7030 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT
, 0));
7031 checkGLcall("glBindFramebuffer()");
7034 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
7035 if (dst_swapchain
&& dst_surface
== ((IWineD3DSwapChainImpl
*)dst_swapchain
)->frontBuffer
7036 && ((IWineD3DSwapChainImpl
*)dst_swapchain
)->backBuffer
) {
7037 glDrawBuffer(GL_BACK
);
7038 checkGLcall("glDrawBuffer()");
7043 static HRESULT WINAPI
IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice
*iface
, DWORD RenderTargetIndex
, IWineD3DSurface
*pRenderTarget
) {
7044 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
7045 WINED3DVIEWPORT viewport
;
7047 TRACE("(%p) : Setting rendertarget %d to %p\n", This
, RenderTargetIndex
, pRenderTarget
);
7049 if (RenderTargetIndex
>= GL_LIMITS(buffers
)) {
7050 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
7051 This
, RenderTargetIndex
, GL_LIMITS(buffers
));
7052 return WINED3DERR_INVALIDCALL
;
7055 /* MSDN says that null disables the render target
7056 but a device must always be associated with a render target
7057 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
7059 if (RenderTargetIndex
== 0 && pRenderTarget
== NULL
) {
7060 FIXME("Trying to set render target 0 to NULL\n");
7061 return WINED3DERR_INVALIDCALL
;
7063 if (pRenderTarget
&& !(((IWineD3DSurfaceImpl
*)pRenderTarget
)->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)) {
7064 FIXME("(%p)Trying to set the render target to a surface(%p) that wasn't created with a usage of WINED3DUSAGE_RENDERTARGET\n",This
,pRenderTarget
);
7065 return WINED3DERR_INVALIDCALL
;
7068 /* If we are trying to set what we already have, don't bother */
7069 if (pRenderTarget
== This
->render_targets
[RenderTargetIndex
]) {
7070 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7073 if(pRenderTarget
) IWineD3DSurface_AddRef(pRenderTarget
);
7074 if(This
->render_targets
[RenderTargetIndex
]) IWineD3DSurface_Release(This
->render_targets
[RenderTargetIndex
]);
7075 This
->render_targets
[RenderTargetIndex
] = pRenderTarget
;
7077 /* Render target 0 is special */
7078 if(RenderTargetIndex
== 0) {
7079 /* Finally, reset the viewport as the MSDN states. */
7080 viewport
.Height
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Height
;
7081 viewport
.Width
= ((IWineD3DSurfaceImpl
*)This
->render_targets
[0])->currentDesc
.Width
;
7084 viewport
.MaxZ
= 1.0f
;
7085 viewport
.MinZ
= 0.0f
;
7086 IWineD3DDeviceImpl_SetViewport(iface
, &viewport
);
7087 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
7088 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
7090 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_VIEWPORT
);
7095 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice
*iface
, IWineD3DSurface
*pNewZStencil
) {
7096 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
7097 HRESULT hr
= WINED3D_OK
;
7098 IWineD3DSurface
*tmp
;
7100 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This
, This
->stencilBufferTarget
, pNewZStencil
);
7102 if (pNewZStencil
== This
->stencilBufferTarget
) {
7103 TRACE("Trying to do a NOP SetRenderTarget operation\n");
7105 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
7106 * depending on the renter target implementation being used.
7107 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
7108 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
7109 * stencil buffer and incur an extra memory overhead
7110 ******************************************************/
7112 if (This
->stencilBufferTarget
) {
7113 if (((IWineD3DSwapChainImpl
*)This
->swapchains
[0])->presentParms
.Flags
& WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
7114 || ((IWineD3DSurfaceImpl
*)This
->stencilBufferTarget
)->Flags
& SFLAG_DISCARD
) {
7115 surface_modify_ds_location(This
->stencilBufferTarget
, SFLAG_DS_DISCARDED
);
7117 ActivateContext(This
, This
->render_targets
[0], CTXUSAGE_RESOURCELOAD
);
7118 surface_load_ds_location(This
->stencilBufferTarget
, SFLAG_DS_OFFSCREEN
);
7119 surface_modify_ds_location(This
->stencilBufferTarget
, SFLAG_DS_OFFSCREEN
);
7123 tmp
= This
->stencilBufferTarget
;
7124 This
->stencilBufferTarget
= pNewZStencil
;
7125 /* should we be calling the parent or the wined3d surface? */
7126 if (NULL
!= This
->stencilBufferTarget
) IWineD3DSurface_AddRef(This
->stencilBufferTarget
);
7127 if (NULL
!= tmp
) IWineD3DSurface_Release(tmp
);
7130 if((!tmp
&& pNewZStencil
) || (!pNewZStencil
&& tmp
)) {
7131 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
7132 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_ZENABLE
));
7133 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_STENCILENABLE
));
7134 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_RENDER(WINED3DRS_STENCILWRITEMASK
));
7141 static HRESULT WINAPI
IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice
* iface
, UINT XHotSpot
,
7142 UINT YHotSpot
, IWineD3DSurface
*pCursorBitmap
) {
7143 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7144 /* TODO: the use of Impl is deprecated. */
7145 IWineD3DSurfaceImpl
* pSur
= (IWineD3DSurfaceImpl
*) pCursorBitmap
;
7146 WINED3DLOCKED_RECT lockedRect
;
7148 TRACE("(%p) : Spot Pos(%u,%u)\n", This
, XHotSpot
, YHotSpot
);
7150 /* some basic validation checks */
7151 if(This
->cursorTexture
) {
7152 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
7154 glDeleteTextures(1, &This
->cursorTexture
);
7156 This
->cursorTexture
= 0;
7159 if ( (pSur
->currentDesc
.Width
== 32) && (pSur
->currentDesc
.Height
== 32) )
7160 This
->haveHardwareCursor
= TRUE
;
7162 This
->haveHardwareCursor
= FALSE
;
7165 WINED3DLOCKED_RECT rect
;
7167 /* MSDN: Cursor must be A8R8G8B8 */
7168 if (WINED3DFMT_A8R8G8B8
!= pSur
->resource
.format_desc
->format
)
7170 ERR("(%p) : surface(%p) has an invalid format\n", This
, pCursorBitmap
);
7171 return WINED3DERR_INVALIDCALL
;
7174 /* MSDN: Cursor must be smaller than the display mode */
7175 if(pSur
->currentDesc
.Width
> This
->ddraw_width
||
7176 pSur
->currentDesc
.Height
> This
->ddraw_height
) {
7177 ERR("(%p) : Surface(%p) is %dx%d pixels, but screen res is %dx%d\n", This
, pSur
, pSur
->currentDesc
.Width
, pSur
->currentDesc
.Height
, This
->ddraw_width
, This
->ddraw_height
);
7178 return WINED3DERR_INVALIDCALL
;
7181 if (!This
->haveHardwareCursor
) {
7182 /* TODO: MSDN: Cursor sizes must be a power of 2 */
7184 /* Do not store the surface's pointer because the application may
7185 * release it after setting the cursor image. Windows doesn't
7186 * addref the set surface, so we can't do this either without
7187 * creating circular refcount dependencies. Copy out the gl texture
7190 This
->cursorWidth
= pSur
->currentDesc
.Width
;
7191 This
->cursorHeight
= pSur
->currentDesc
.Height
;
7192 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap
, &rect
, NULL
, WINED3DLOCK_READONLY
)))
7194 const struct GlPixelFormatDesc
*glDesc
= getFormatDescEntry(WINED3DFMT_A8R8G8B8
, &GLINFO_LOCATION
);
7195 char *mem
, *bits
= rect
.pBits
;
7196 GLint intfmt
= glDesc
->glInternal
;
7197 GLint format
= glDesc
->glFormat
;
7198 GLint type
= glDesc
->glType
;
7199 INT height
= This
->cursorHeight
;
7200 INT width
= This
->cursorWidth
;
7201 INT bpp
= glDesc
->byte_count
;
7204 /* Reformat the texture memory (pitch and width can be
7206 mem
= HeapAlloc(GetProcessHeap(), 0, width
* height
* bpp
);
7207 for(i
= 0; i
< height
; i
++)
7208 memcpy(&mem
[width
* bpp
* i
], &bits
[rect
.Pitch
* i
], width
* bpp
);
7209 IWineD3DSurface_UnlockRect(pCursorBitmap
);
7212 if(GL_SUPPORT(APPLE_CLIENT_STORAGE
)) {
7213 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
7214 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
7217 /* Make sure that a proper texture unit is selected */
7218 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
7219 checkGLcall("glActiveTextureARB");
7220 sampler
= This
->rev_tex_unit_map
[0];
7221 if (sampler
!= -1) {
7222 IWineD3DDeviceImpl_MarkStateDirty(This
, STATE_SAMPLER(sampler
));
7224 /* Create a new cursor texture */
7225 glGenTextures(1, &This
->cursorTexture
);
7226 checkGLcall("glGenTextures");
7227 glBindTexture(GL_TEXTURE_2D
, This
->cursorTexture
);
7228 checkGLcall("glBindTexture");
7229 /* Copy the bitmap memory into the cursor texture */
7230 glTexImage2D(GL_TEXTURE_2D
, 0, intfmt
, width
, height
, 0, format
, type
, mem
);
7231 HeapFree(GetProcessHeap(), 0, mem
);
7232 checkGLcall("glTexImage2D");
7234 if(GL_SUPPORT(APPLE_CLIENT_STORAGE
)) {
7235 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
7236 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
7243 FIXME("A cursor texture was not returned.\n");
7244 This
->cursorTexture
= 0;
7249 /* Draw a hardware cursor */
7250 ICONINFO cursorInfo
;
7252 /* Create and clear maskBits because it is not needed for
7253 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
7255 DWORD
*maskBits
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
7256 (pSur
->currentDesc
.Width
* pSur
->currentDesc
.Height
/ 8));
7257 IWineD3DSurface_LockRect(pCursorBitmap
, &lockedRect
, NULL
,
7258 WINED3DLOCK_NO_DIRTY_UPDATE
|
7259 WINED3DLOCK_READONLY
7261 TRACE("width: %i height: %i\n", pSur
->currentDesc
.Width
,
7262 pSur
->currentDesc
.Height
);
7264 cursorInfo
.fIcon
= FALSE
;
7265 cursorInfo
.xHotspot
= XHotSpot
;
7266 cursorInfo
.yHotspot
= YHotSpot
;
7267 cursorInfo
.hbmMask
= CreateBitmap(pSur
->currentDesc
.Width
,
7268 pSur
->currentDesc
.Height
, 1,
7270 cursorInfo
.hbmColor
= CreateBitmap(pSur
->currentDesc
.Width
,
7271 pSur
->currentDesc
.Height
, 1,
7272 32, lockedRect
.pBits
);
7273 IWineD3DSurface_UnlockRect(pCursorBitmap
);
7274 /* Create our cursor and clean up. */
7275 cursor
= CreateIconIndirect(&cursorInfo
);
7277 if (cursorInfo
.hbmMask
) DeleteObject(cursorInfo
.hbmMask
);
7278 if (cursorInfo
.hbmColor
) DeleteObject(cursorInfo
.hbmColor
);
7279 if (This
->hardwareCursor
) DestroyCursor(This
->hardwareCursor
);
7280 This
->hardwareCursor
= cursor
;
7281 HeapFree(GetProcessHeap(), 0, maskBits
);
7285 This
->xHotSpot
= XHotSpot
;
7286 This
->yHotSpot
= YHotSpot
;
7290 static void WINAPI
IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice
* iface
, int XScreenSpace
, int YScreenSpace
, DWORD Flags
) {
7291 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7292 TRACE("(%p) : SetPos to (%u,%u)\n", This
, XScreenSpace
, YScreenSpace
);
7294 This
->xScreenSpace
= XScreenSpace
;
7295 This
->yScreenSpace
= YScreenSpace
;
7301 static BOOL WINAPI
IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice
* iface
, BOOL bShow
) {
7302 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7303 BOOL oldVisible
= This
->bCursorVisible
;
7306 TRACE("(%p) : visible(%d)\n", This
, bShow
);
7309 * When ShowCursor is first called it should make the cursor appear at the OS's last
7310 * known cursor position. Because of this, some applications just repetitively call
7311 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
7314 This
->xScreenSpace
= pt
.x
;
7315 This
->yScreenSpace
= pt
.y
;
7317 if (This
->haveHardwareCursor
) {
7318 This
->bCursorVisible
= bShow
;
7320 SetCursor(This
->hardwareCursor
);
7326 if (This
->cursorTexture
)
7327 This
->bCursorVisible
= bShow
;
7333 static HRESULT WINAPI
IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice
* iface
) {
7334 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7335 IWineD3DResourceImpl
*resource
;
7336 TRACE("(%p) : state (%u)\n", This
, This
->state
);
7338 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
7339 switch (This
->state
) {
7342 case WINED3DERR_DEVICELOST
:
7344 LIST_FOR_EACH_ENTRY(resource
, &This
->resources
, IWineD3DResourceImpl
, resource
.resource_list_entry
) {
7345 if (resource
->resource
.pool
== WINED3DPOOL_DEFAULT
)
7346 return WINED3DERR_DEVICENOTRESET
;
7348 return WINED3DERR_DEVICELOST
;
7350 case WINED3DERR_DRIVERINTERNALERROR
:
7351 return WINED3DERR_DRIVERINTERNALERROR
;
7355 return WINED3DERR_DRIVERINTERNALERROR
;
7359 static HRESULT WINAPI
IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice
* iface
) {
7360 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7361 /** FIXME: Resource tracking needs to be done,
7362 * The closes we can do to this is set the priorities of all managed textures low
7363 * and then reset them.
7364 ***********************************************************/
7365 FIXME("(%p) : stub\n", This
);
7369 static void updateSurfaceDesc(IWineD3DSurfaceImpl
*surface
, const WINED3DPRESENT_PARAMETERS
* pPresentationParameters
)
7371 IWineD3DDeviceImpl
*This
= surface
->resource
.wineD3DDevice
; /* for GL_SUPPORT */
7373 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7374 if(surface
->Flags
& SFLAG_DIBSECTION
) {
7375 /* Release the DC */
7376 SelectObject(surface
->hDC
, surface
->dib
.holdbitmap
);
7377 DeleteDC(surface
->hDC
);
7378 /* Release the DIB section */
7379 DeleteObject(surface
->dib
.DIBsection
);
7380 surface
->dib
.bitmap_data
= NULL
;
7381 surface
->resource
.allocatedMemory
= NULL
;
7382 surface
->Flags
&= ~SFLAG_DIBSECTION
;
7384 surface
->currentDesc
.Width
= pPresentationParameters
->BackBufferWidth
;
7385 surface
->currentDesc
.Height
= pPresentationParameters
->BackBufferHeight
;
7386 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO
) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE
) ||
7387 GL_SUPPORT(WINE_NORMALIZED_TEXRECT
)) {
7388 surface
->pow2Width
= pPresentationParameters
->BackBufferWidth
;
7389 surface
->pow2Height
= pPresentationParameters
->BackBufferHeight
;
7391 surface
->pow2Width
= surface
->pow2Height
= 1;
7392 while (surface
->pow2Width
< pPresentationParameters
->BackBufferWidth
) surface
->pow2Width
<<= 1;
7393 while (surface
->pow2Height
< pPresentationParameters
->BackBufferHeight
) surface
->pow2Height
<<= 1;
7395 surface
->glRect
.left
= 0;
7396 surface
->glRect
.top
= 0;
7397 surface
->glRect
.right
= surface
->pow2Width
;
7398 surface
->glRect
.bottom
= surface
->pow2Height
;
7400 if(surface
->glDescription
.textureName
) {
7401 ActivateContext(This
, This
->lastActiveRenderTarget
, CTXUSAGE_RESOURCELOAD
);
7403 glDeleteTextures(1, &surface
->glDescription
.textureName
);
7405 surface
->glDescription
.textureName
= 0;
7406 surface
->Flags
&= ~SFLAG_CLIENT
;
7408 if(surface
->pow2Width
!= pPresentationParameters
->BackBufferWidth
||
7409 surface
->pow2Height
!= pPresentationParameters
->BackBufferHeight
) {
7410 surface
->Flags
|= SFLAG_NONPOW2
;
7412 surface
->Flags
&= ~SFLAG_NONPOW2
;
7414 HeapFree(GetProcessHeap(), 0, surface
->resource
.heapMemory
);
7415 surface
->resource
.allocatedMemory
= NULL
;
7416 surface
->resource
.heapMemory
= NULL
;
7417 surface
->resource
.size
= IWineD3DSurface_GetPitch((IWineD3DSurface
*) surface
) * surface
->pow2Width
;
7418 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7419 if (surface
->resource
.usage
& WINED3DUSAGE_DEPTHSTENCIL
) {
7420 IWineD3DSurface_ModifyLocation((IWineD3DSurface
*) surface
, SFLAG_INSYSMEM
, TRUE
);
7422 IWineD3DSurface_ModifyLocation((IWineD3DSurface
*) surface
, SFLAG_INDRAWABLE
, TRUE
);
7426 static HRESULT WINAPI
reset_unload_resources(IWineD3DResource
*resource
, void *data
) {
7427 TRACE("Unloading resource %p\n", resource
);
7428 IWineD3DResource_UnLoad(resource
);
7429 IWineD3DResource_Release(resource
);
7433 static BOOL
is_display_mode_supported(IWineD3DDeviceImpl
*This
, const WINED3DPRESENT_PARAMETERS
*pp
)
7436 WINED3DDISPLAYMODE m
;
7439 /* All Windowed modes are supported, as is leaving the current mode */
7440 if(pp
->Windowed
) return TRUE
;
7441 if(!pp
->BackBufferWidth
) return TRUE
;
7442 if(!pp
->BackBufferHeight
) return TRUE
;
7444 count
= IWineD3D_GetAdapterModeCount(This
->wineD3D
, This
->adapter
->num
, WINED3DFMT_UNKNOWN
);
7445 for(i
= 0; i
< count
; i
++) {
7446 memset(&m
, 0, sizeof(m
));
7447 hr
= IWineD3D_EnumAdapterModes(This
->wineD3D
, This
->adapter
->num
, WINED3DFMT_UNKNOWN
, i
, &m
);
7449 ERR("EnumAdapterModes failed\n");
7451 if(m
.Width
== pp
->BackBufferWidth
&& m
.Height
== pp
->BackBufferHeight
) {
7452 /* Mode found, it is supported */
7456 /* Mode not found -> not supported */
7460 void delete_opengl_contexts(IWineD3DDevice
*iface
, IWineD3DSwapChain
*swapchain_iface
) {
7461 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7462 IWineD3DSwapChainImpl
*swapchain
= (IWineD3DSwapChainImpl
*) swapchain_iface
;
7464 IWineD3DBaseShaderImpl
*shader
;
7466 IWineD3DDevice_EnumResources(iface
, reset_unload_resources
, NULL
);
7467 LIST_FOR_EACH_ENTRY(shader
, &This
->shaders
, IWineD3DBaseShaderImpl
, baseShader
.shader_list_entry
) {
7468 This
->shader_backend
->shader_destroy((IWineD3DBaseShader
*) shader
);
7472 if(This
->depth_blt_texture
) {
7473 glDeleteTextures(1, &This
->depth_blt_texture
);
7474 This
->depth_blt_texture
= 0;
7476 if (This
->depth_blt_rb
) {
7477 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This
->depth_blt_rb
));
7478 This
->depth_blt_rb
= 0;
7479 This
->depth_blt_rb_w
= 0;
7480 This
->depth_blt_rb_h
= 0;
7484 This
->blitter
->free_private(iface
);
7485 This
->frag_pipe
->free_private(iface
);
7486 This
->shader_backend
->shader_free_private(iface
);
7489 for (i
= 0; i
< GL_LIMITS(textures
); i
++) {
7490 /* Textures are recreated below */
7491 glDeleteTextures(1, &This
->dummyTextureName
[i
]);
7492 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7493 This
->dummyTextureName
[i
] = 0;
7497 while(This
->numContexts
) {
7498 DestroyContext(This
, This
->contexts
[0]);
7500 This
->activeContext
= NULL
;
7501 HeapFree(GetProcessHeap(), 0, swapchain
->context
);
7502 swapchain
->context
= NULL
;
7503 swapchain
->num_contexts
= 0;
7506 HRESULT
create_primary_opengl_context(IWineD3DDevice
*iface
, IWineD3DSwapChain
*swapchain_iface
) {
7507 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7508 IWineD3DSwapChainImpl
*swapchain
= (IWineD3DSwapChainImpl
*) swapchain_iface
;
7510 IWineD3DSurfaceImpl
*target
;
7512 /* Recreate the primary swapchain's context */
7513 swapchain
->context
= HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain
->context
));
7514 if(swapchain
->backBuffer
) {
7515 target
= (IWineD3DSurfaceImpl
*) swapchain
->backBuffer
[0];
7517 target
= (IWineD3DSurfaceImpl
*) swapchain
->frontBuffer
;
7519 swapchain
->context
[0] = CreateContext(This
, target
, swapchain
->win_handle
, FALSE
,
7520 &swapchain
->presentParms
);
7521 swapchain
->num_contexts
= 1;
7522 This
->activeContext
= swapchain
->context
[0];
7524 create_dummy_textures(This
);
7526 hr
= This
->shader_backend
->shader_alloc_private(iface
);
7528 ERR("Failed to recreate shader private data\n");
7531 hr
= This
->frag_pipe
->alloc_private(iface
);
7533 TRACE("Fragment pipeline private data couldn't be allocated\n");
7536 hr
= This
->blitter
->alloc_private(iface
);
7538 TRACE("Blitter private data couldn't be allocated\n");
7545 This
->blitter
->free_private(iface
);
7546 This
->frag_pipe
->free_private(iface
);
7547 This
->shader_backend
->shader_free_private(iface
);
7551 static HRESULT WINAPI
IWineD3DDeviceImpl_Reset(IWineD3DDevice
* iface
, WINED3DPRESENT_PARAMETERS
* pPresentationParameters
) {
7552 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7553 IWineD3DSwapChainImpl
*swapchain
;
7555 BOOL DisplayModeChanged
= FALSE
;
7556 WINED3DDISPLAYMODE mode
;
7557 TRACE("(%p)\n", This
);
7559 hr
= IWineD3DDevice_GetSwapChain(iface
, 0, (IWineD3DSwapChain
**) &swapchain
);
7561 ERR("Failed to get the first implicit swapchain\n");
7565 if(!is_display_mode_supported(This
, pPresentationParameters
)) {
7566 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7567 WARN("Requested mode: %d, %d\n", pPresentationParameters
->BackBufferWidth
,
7568 pPresentationParameters
->BackBufferHeight
);
7569 IWineD3DSwapChain_Release((IWineD3DSwapChain
*)swapchain
);
7570 return WINED3DERR_INVALIDCALL
;
7573 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7574 * on an existing gl context, so there's no real need for recreation.
7576 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7578 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7580 TRACE("New params:\n");
7581 TRACE("BackBufferWidth = %d\n", pPresentationParameters
->BackBufferWidth
);
7582 TRACE("BackBufferHeight = %d\n", pPresentationParameters
->BackBufferHeight
);
7583 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters
->BackBufferFormat
));
7584 TRACE("BackBufferCount = %d\n", pPresentationParameters
->BackBufferCount
);
7585 TRACE("MultiSampleType = %d\n", pPresentationParameters
->MultiSampleType
);
7586 TRACE("MultiSampleQuality = %d\n", pPresentationParameters
->MultiSampleQuality
);
7587 TRACE("SwapEffect = %d\n", pPresentationParameters
->SwapEffect
);
7588 TRACE("hDeviceWindow = %p\n", pPresentationParameters
->hDeviceWindow
);
7589 TRACE("Windowed = %s\n", pPresentationParameters
->Windowed
? "true" : "false");
7590 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters
->EnableAutoDepthStencil
? "true" : "false");
7591 TRACE("Flags = %08x\n", pPresentationParameters
->Flags
);
7592 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters
->FullScreen_RefreshRateInHz
);
7593 TRACE("PresentationInterval = %d\n", pPresentationParameters
->PresentationInterval
);
7595 /* No special treatment of these parameters. Just store them */
7596 swapchain
->presentParms
.SwapEffect
= pPresentationParameters
->SwapEffect
;
7597 swapchain
->presentParms
.Flags
= pPresentationParameters
->Flags
;
7598 swapchain
->presentParms
.PresentationInterval
= pPresentationParameters
->PresentationInterval
;
7599 swapchain
->presentParms
.FullScreen_RefreshRateInHz
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
7601 /* What to do about these? */
7602 if(pPresentationParameters
->BackBufferCount
!= 0 &&
7603 pPresentationParameters
->BackBufferCount
!= swapchain
->presentParms
.BackBufferCount
) {
7604 ERR("Cannot change the back buffer count yet\n");
7606 if(pPresentationParameters
->BackBufferFormat
!= WINED3DFMT_UNKNOWN
&&
7607 pPresentationParameters
->BackBufferFormat
!= swapchain
->presentParms
.BackBufferFormat
) {
7608 ERR("Cannot change the back buffer format yet\n");
7610 if(pPresentationParameters
->hDeviceWindow
!= NULL
&&
7611 pPresentationParameters
->hDeviceWindow
!= swapchain
->presentParms
.hDeviceWindow
) {
7612 ERR("Cannot change the device window yet\n");
7614 if (pPresentationParameters
->EnableAutoDepthStencil
&& !This
->auto_depth_stencil_buffer
) {
7617 TRACE("Creating the depth stencil buffer\n");
7619 hrc
= IWineD3DDeviceParent_CreateDepthStencilSurface(This
->device_parent
,
7621 pPresentationParameters
->BackBufferWidth
,
7622 pPresentationParameters
->BackBufferHeight
,
7623 pPresentationParameters
->AutoDepthStencilFormat
,
7624 pPresentationParameters
->MultiSampleType
,
7625 pPresentationParameters
->MultiSampleQuality
,
7627 &This
->auto_depth_stencil_buffer
);
7630 ERR("Failed to create the depth stencil buffer\n");
7631 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
7632 return WINED3DERR_INVALIDCALL
;
7636 /* Reset the depth stencil */
7637 if (pPresentationParameters
->EnableAutoDepthStencil
)
7638 IWineD3DDevice_SetDepthStencilSurface(iface
, This
->auto_depth_stencil_buffer
);
7640 IWineD3DDevice_SetDepthStencilSurface(iface
, NULL
);
7642 delete_opengl_contexts(iface
, (IWineD3DSwapChain
*) swapchain
);
7644 if(pPresentationParameters
->Windowed
) {
7645 mode
.Width
= swapchain
->orig_width
;
7646 mode
.Height
= swapchain
->orig_height
;
7647 mode
.RefreshRate
= 0;
7648 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
7650 mode
.Width
= pPresentationParameters
->BackBufferWidth
;
7651 mode
.Height
= pPresentationParameters
->BackBufferHeight
;
7652 mode
.RefreshRate
= pPresentationParameters
->FullScreen_RefreshRateInHz
;
7653 mode
.Format
= swapchain
->presentParms
.BackBufferFormat
;
7656 /* Should Width == 800 && Height == 0 set 800x600? */
7657 if(pPresentationParameters
->BackBufferWidth
!= 0 && pPresentationParameters
->BackBufferHeight
!= 0 &&
7658 (pPresentationParameters
->BackBufferWidth
!= swapchain
->presentParms
.BackBufferWidth
||
7659 pPresentationParameters
->BackBufferHeight
!= swapchain
->presentParms
.BackBufferHeight
))
7663 if(!pPresentationParameters
->Windowed
) {
7664 DisplayModeChanged
= TRUE
;
7666 swapchain
->presentParms
.BackBufferWidth
= pPresentationParameters
->BackBufferWidth
;
7667 swapchain
->presentParms
.BackBufferHeight
= pPresentationParameters
->BackBufferHeight
;
7669 updateSurfaceDesc((IWineD3DSurfaceImpl
*)swapchain
->frontBuffer
, pPresentationParameters
);
7670 for(i
= 0; i
< swapchain
->presentParms
.BackBufferCount
; i
++) {
7671 updateSurfaceDesc((IWineD3DSurfaceImpl
*)swapchain
->backBuffer
[i
], pPresentationParameters
);
7673 if(This
->auto_depth_stencil_buffer
) {
7674 updateSurfaceDesc((IWineD3DSurfaceImpl
*)This
->auto_depth_stencil_buffer
, pPresentationParameters
);
7678 if((pPresentationParameters
->Windowed
&& !swapchain
->presentParms
.Windowed
) ||
7679 (swapchain
->presentParms
.Windowed
&& !pPresentationParameters
->Windowed
) ||
7680 DisplayModeChanged
) {
7682 IWineD3DDevice_SetDisplayMode(iface
, 0, &mode
);
7684 if(swapchain
->win_handle
&& !pPresentationParameters
->Windowed
) {
7685 if(swapchain
->presentParms
.Windowed
) {
7686 /* switch from windowed to fs */
7687 IWineD3DDeviceImpl_SetupFullscreenWindow(iface
, swapchain
->win_handle
,
7688 pPresentationParameters
->BackBufferWidth
,
7689 pPresentationParameters
->BackBufferHeight
);
7691 /* Fullscreen -> fullscreen mode change */
7692 MoveWindow(swapchain
->win_handle
, 0, 0,
7693 pPresentationParameters
->BackBufferWidth
, pPresentationParameters
->BackBufferHeight
,
7696 } else if(swapchain
->win_handle
&& !swapchain
->presentParms
.Windowed
) {
7697 /* Fullscreen -> windowed switch */
7698 IWineD3DDeviceImpl_RestoreWindow(iface
, swapchain
->win_handle
);
7700 swapchain
->presentParms
.Windowed
= pPresentationParameters
->Windowed
;
7701 } else if(!pPresentationParameters
->Windowed
) {
7702 DWORD style
= This
->style
, exStyle
= This
->exStyle
;
7703 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7704 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7705 * Reset to clear up their mess. Guild Wars also loses the device during that.
7709 IWineD3DDeviceImpl_SetupFullscreenWindow(iface
, swapchain
->win_handle
,
7710 pPresentationParameters
->BackBufferWidth
,
7711 pPresentationParameters
->BackBufferHeight
);
7712 This
->style
= style
;
7713 This
->exStyle
= exStyle
;
7716 TRACE("Resetting stateblock\n");
7717 IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->updateStateBlock
);
7718 IWineD3DStateBlock_Release((IWineD3DStateBlock
*)This
->stateBlock
);
7720 /* Note: No parent needed for initial internal stateblock */
7721 hr
= IWineD3DDevice_CreateStateBlock(iface
, WINED3DSBT_INIT
, (IWineD3DStateBlock
**)&This
->stateBlock
, NULL
);
7722 if (FAILED(hr
)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr
);
7723 else TRACE("Created stateblock %p\n", This
->stateBlock
);
7724 This
->updateStateBlock
= This
->stateBlock
;
7725 IWineD3DStateBlock_AddRef((IWineD3DStateBlock
*)This
->updateStateBlock
);
7727 hr
= IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock
*) This
->stateBlock
);
7729 ERR("Resetting the stateblock failed with error 0x%08x\n", hr
);
7732 hr
= create_primary_opengl_context(iface
, (IWineD3DSwapChain
*) swapchain
);
7733 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
7735 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7741 static HRESULT WINAPI
IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice
*iface
, BOOL bEnableDialogs
) {
7742 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
7743 /** FIXME: always true at the moment **/
7744 if(!bEnableDialogs
) {
7745 FIXME("(%p) Dialogs cannot be disabled yet\n", This
);
7751 static HRESULT WINAPI
IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice
*iface
, WINED3DDEVICE_CREATION_PARAMETERS
*pParameters
) {
7752 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7753 TRACE("(%p) : pParameters %p\n", This
, pParameters
);
7755 *pParameters
= This
->createParms
;
7759 static void WINAPI
IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice
* iface
, UINT iSwapChain
, DWORD Flags
, CONST WINED3DGAMMARAMP
* pRamp
) {
7760 IWineD3DSwapChain
*swapchain
;
7762 TRACE("Relaying to swapchain\n");
7764 if (IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
) == WINED3D_OK
) {
7765 IWineD3DSwapChain_SetGammaRamp(swapchain
, Flags
, pRamp
);
7766 IWineD3DSwapChain_Release(swapchain
);
7771 static void WINAPI
IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice
*iface
, UINT iSwapChain
, WINED3DGAMMARAMP
* pRamp
) {
7772 IWineD3DSwapChain
*swapchain
;
7774 TRACE("Relaying to swapchain\n");
7776 if (IWineD3DDeviceImpl_GetSwapChain(iface
, iSwapChain
, &swapchain
) == WINED3D_OK
) {
7777 IWineD3DSwapChain_GetGammaRamp(swapchain
, pRamp
);
7778 IWineD3DSwapChain_Release(swapchain
);
7784 /** ********************************************************
7785 * Notification functions
7786 ** ********************************************************/
7787 /** This function must be called in the release of a resource when ref == 0,
7788 * the contents of resource must still be correct,
7789 * any handles to other resource held by the caller must be closed
7790 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7791 *****************************************************/
7792 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
7793 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
7795 TRACE("(%p) : Adding Resource %p\n", This
, resource
);
7796 list_add_head(&This
->resources
, &((IWineD3DResourceImpl
*) resource
)->resource
.resource_list_entry
);
7799 static void IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
7800 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*)iface
;
7802 TRACE("(%p) : Removing resource %p\n", This
, resource
);
7804 list_remove(&((IWineD3DResourceImpl
*) resource
)->resource
.resource_list_entry
);
7808 static void WINAPI
IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice
*iface
, IWineD3DResource
*resource
){
7809 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7810 WINED3DRESOURCETYPE type
= IWineD3DResource_GetType(resource
);
7813 TRACE("(%p) : resource %p\n", This
, resource
);
7815 context_resource_released(iface
, resource
, type
);
7818 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7819 case WINED3DRTYPE_SURFACE
: {
7822 /* Cleanup any FBO attachments if d3d is enabled */
7823 if(This
->d3d_initialized
) {
7824 if((IWineD3DSurface
*)resource
== This
->lastActiveRenderTarget
) {
7825 IWineD3DSwapChainImpl
*swapchain
= This
->swapchains
? (IWineD3DSwapChainImpl
*) This
->swapchains
[0] : NULL
;
7827 TRACE("Last active render target destroyed\n");
7828 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7829 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7830 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7831 * and the lastActiveRenderTarget member shouldn't matter
7834 if(swapchain
->backBuffer
&& swapchain
->backBuffer
[0] != (IWineD3DSurface
*)resource
) {
7835 TRACE("Activating primary back buffer\n");
7836 ActivateContext(This
, swapchain
->backBuffer
[0], CTXUSAGE_RESOURCELOAD
);
7837 } else if(!swapchain
->backBuffer
&& swapchain
->frontBuffer
!= (IWineD3DSurface
*)resource
) {
7838 /* Single buffering environment */
7839 TRACE("Activating primary front buffer\n");
7840 ActivateContext(This
, swapchain
->frontBuffer
, CTXUSAGE_RESOURCELOAD
);
7842 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7843 /* Implicit render target destroyed, that means the device is being destroyed
7844 * whatever we set here, it shouldn't matter
7846 This
->lastActiveRenderTarget
= (IWineD3DSurface
*) 0xdeadbabe;
7849 /* May happen during ddraw uninitialization */
7850 TRACE("Render target set, but swapchain does not exist!\n");
7851 This
->lastActiveRenderTarget
= (IWineD3DSurface
*) 0xdeadcafe;
7855 for (i
= 0; i
< GL_LIMITS(buffers
); ++i
) {
7856 if (This
->render_targets
[i
] == (IWineD3DSurface
*)resource
) {
7857 This
->render_targets
[i
] = NULL
;
7860 if (This
->stencilBufferTarget
== (IWineD3DSurface
*)resource
) {
7861 This
->stencilBufferTarget
= NULL
;
7867 case WINED3DRTYPE_TEXTURE
:
7868 case WINED3DRTYPE_CUBETEXTURE
:
7869 case WINED3DRTYPE_VOLUMETEXTURE
:
7870 for (counter
= 0; counter
< MAX_COMBINED_SAMPLERS
; counter
++) {
7871 if (This
->stateBlock
!= NULL
&& This
->stateBlock
->textures
[counter
] == (IWineD3DBaseTexture
*)resource
) {
7872 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter
, resource
);
7873 This
->stateBlock
->textures
[counter
] = NULL
;
7875 if (This
->updateStateBlock
!= This
->stateBlock
){
7876 if (This
->updateStateBlock
->textures
[counter
] == (IWineD3DBaseTexture
*)resource
) {
7877 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter
, resource
);
7878 This
->updateStateBlock
->textures
[counter
] = NULL
;
7883 case WINED3DRTYPE_VOLUME
:
7884 /* TODO: nothing really? */
7886 case WINED3DRTYPE_BUFFER
:
7889 TRACE("Cleaning up stream pointers\n");
7891 for(streamNumber
= 0; streamNumber
< MAX_STREAMS
; streamNumber
++){
7892 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7893 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7895 if (This
->updateStateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
7896 if ((IWineD3DResource
*)This
->updateStateBlock
->streamSource
[streamNumber
] == resource
) {
7897 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber
);
7898 This
->updateStateBlock
->streamSource
[streamNumber
] = 0;
7899 /* Set changed flag? */
7902 if (This
->stateBlock
!= NULL
) { /* only happens if there is an error in the application, or on reset/release (because we don't manage internal tracking properly) */
7903 if ((IWineD3DResource
*)This
->stateBlock
->streamSource
[streamNumber
] == resource
) {
7904 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber
);
7905 This
->stateBlock
->streamSource
[streamNumber
] = 0;
7910 if (This
->updateStateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
7911 if (This
->updateStateBlock
->pIndexData
== (IWineD3DBuffer
*)resource
) {
7912 This
->updateStateBlock
->pIndexData
= NULL
;
7915 if (This
->stateBlock
!= NULL
) { /* ==NULL when device is being destroyed */
7916 if (This
->stateBlock
->pIndexData
== (IWineD3DBuffer
*)resource
) {
7917 This
->stateBlock
->pIndexData
= NULL
;
7924 FIXME("(%p) unknown resource type %p %u\n", This
, resource
, IWineD3DResource_GetType(resource
));
7929 /* Remove the resource from the resourceStore */
7930 IWineD3DDeviceImpl_RemoveResource(iface
, resource
);
7932 TRACE("Resource released\n");
7936 static HRESULT WINAPI
IWineD3DDeviceImpl_EnumResources(IWineD3DDevice
*iface
, D3DCB_ENUMRESOURCES pCallback
, void *pData
) {
7937 IWineD3DDeviceImpl
*This
= (IWineD3DDeviceImpl
*) iface
;
7938 IWineD3DResourceImpl
*resource
, *cursor
;
7940 TRACE("(%p)->(%p,%p)\n", This
, pCallback
, pData
);
7942 LIST_FOR_EACH_ENTRY_SAFE(resource
, cursor
, &This
->resources
, IWineD3DResourceImpl
, resource
.resource_list_entry
) {
7943 TRACE("enumerating resource %p\n", resource
);
7944 IWineD3DResource_AddRef((IWineD3DResource
*) resource
);
7945 ret
= pCallback((IWineD3DResource
*) resource
, pData
);
7946 if(ret
== S_FALSE
) {
7947 TRACE("Canceling enumeration\n");
7954 /**********************************************************
7955 * IWineD3DDevice VTbl follows
7956 **********************************************************/
7958 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl
=
7960 /*** IUnknown methods ***/
7961 IWineD3DDeviceImpl_QueryInterface
,
7962 IWineD3DDeviceImpl_AddRef
,
7963 IWineD3DDeviceImpl_Release
,
7964 /*** IWineD3DDevice methods ***/
7965 IWineD3DDeviceImpl_GetParent
,
7966 /*** Creation methods**/
7967 IWineD3DDeviceImpl_CreateBuffer
,
7968 IWineD3DDeviceImpl_CreateVertexBuffer
,
7969 IWineD3DDeviceImpl_CreateIndexBuffer
,
7970 IWineD3DDeviceImpl_CreateStateBlock
,
7971 IWineD3DDeviceImpl_CreateSurface
,
7972 IWineD3DDeviceImpl_CreateRendertargetView
,
7973 IWineD3DDeviceImpl_CreateTexture
,
7974 IWineD3DDeviceImpl_CreateVolumeTexture
,
7975 IWineD3DDeviceImpl_CreateVolume
,
7976 IWineD3DDeviceImpl_CreateCubeTexture
,
7977 IWineD3DDeviceImpl_CreateQuery
,
7978 IWineD3DDeviceImpl_CreateSwapChain
,
7979 IWineD3DDeviceImpl_CreateVertexDeclaration
,
7980 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF
,
7981 IWineD3DDeviceImpl_CreateVertexShader
,
7982 IWineD3DDeviceImpl_CreatePixelShader
,
7983 IWineD3DDeviceImpl_CreatePalette
,
7984 /*** Odd functions **/
7985 IWineD3DDeviceImpl_Init3D
,
7986 IWineD3DDeviceImpl_InitGDI
,
7987 IWineD3DDeviceImpl_Uninit3D
,
7988 IWineD3DDeviceImpl_UninitGDI
,
7989 IWineD3DDeviceImpl_SetMultithreaded
,
7990 IWineD3DDeviceImpl_EvictManagedResources
,
7991 IWineD3DDeviceImpl_GetAvailableTextureMem
,
7992 IWineD3DDeviceImpl_GetBackBuffer
,
7993 IWineD3DDeviceImpl_GetCreationParameters
,
7994 IWineD3DDeviceImpl_GetDeviceCaps
,
7995 IWineD3DDeviceImpl_GetDirect3D
,
7996 IWineD3DDeviceImpl_GetDisplayMode
,
7997 IWineD3DDeviceImpl_SetDisplayMode
,
7998 IWineD3DDeviceImpl_GetNumberOfSwapChains
,
7999 IWineD3DDeviceImpl_GetRasterStatus
,
8000 IWineD3DDeviceImpl_GetSwapChain
,
8001 IWineD3DDeviceImpl_Reset
,
8002 IWineD3DDeviceImpl_SetDialogBoxMode
,
8003 IWineD3DDeviceImpl_SetCursorProperties
,
8004 IWineD3DDeviceImpl_SetCursorPosition
,
8005 IWineD3DDeviceImpl_ShowCursor
,
8006 IWineD3DDeviceImpl_TestCooperativeLevel
,
8007 /*** Getters and setters **/
8008 IWineD3DDeviceImpl_SetClipPlane
,
8009 IWineD3DDeviceImpl_GetClipPlane
,
8010 IWineD3DDeviceImpl_SetClipStatus
,
8011 IWineD3DDeviceImpl_GetClipStatus
,
8012 IWineD3DDeviceImpl_SetCurrentTexturePalette
,
8013 IWineD3DDeviceImpl_GetCurrentTexturePalette
,
8014 IWineD3DDeviceImpl_SetDepthStencilSurface
,
8015 IWineD3DDeviceImpl_GetDepthStencilSurface
,
8016 IWineD3DDeviceImpl_SetGammaRamp
,
8017 IWineD3DDeviceImpl_GetGammaRamp
,
8018 IWineD3DDeviceImpl_SetIndices
,
8019 IWineD3DDeviceImpl_GetIndices
,
8020 IWineD3DDeviceImpl_SetBaseVertexIndex
,
8021 IWineD3DDeviceImpl_GetBaseVertexIndex
,
8022 IWineD3DDeviceImpl_SetLight
,
8023 IWineD3DDeviceImpl_GetLight
,
8024 IWineD3DDeviceImpl_SetLightEnable
,
8025 IWineD3DDeviceImpl_GetLightEnable
,
8026 IWineD3DDeviceImpl_SetMaterial
,
8027 IWineD3DDeviceImpl_GetMaterial
,
8028 IWineD3DDeviceImpl_SetNPatchMode
,
8029 IWineD3DDeviceImpl_GetNPatchMode
,
8030 IWineD3DDeviceImpl_SetPaletteEntries
,
8031 IWineD3DDeviceImpl_GetPaletteEntries
,
8032 IWineD3DDeviceImpl_SetPixelShader
,
8033 IWineD3DDeviceImpl_GetPixelShader
,
8034 IWineD3DDeviceImpl_SetPixelShaderConstantB
,
8035 IWineD3DDeviceImpl_GetPixelShaderConstantB
,
8036 IWineD3DDeviceImpl_SetPixelShaderConstantI
,
8037 IWineD3DDeviceImpl_GetPixelShaderConstantI
,
8038 IWineD3DDeviceImpl_SetPixelShaderConstantF
,
8039 IWineD3DDeviceImpl_GetPixelShaderConstantF
,
8040 IWineD3DDeviceImpl_SetRenderState
,
8041 IWineD3DDeviceImpl_GetRenderState
,
8042 IWineD3DDeviceImpl_SetRenderTarget
,
8043 IWineD3DDeviceImpl_GetRenderTarget
,
8044 IWineD3DDeviceImpl_SetFrontBackBuffers
,
8045 IWineD3DDeviceImpl_SetSamplerState
,
8046 IWineD3DDeviceImpl_GetSamplerState
,
8047 IWineD3DDeviceImpl_SetScissorRect
,
8048 IWineD3DDeviceImpl_GetScissorRect
,
8049 IWineD3DDeviceImpl_SetSoftwareVertexProcessing
,
8050 IWineD3DDeviceImpl_GetSoftwareVertexProcessing
,
8051 IWineD3DDeviceImpl_SetStreamSource
,
8052 IWineD3DDeviceImpl_GetStreamSource
,
8053 IWineD3DDeviceImpl_SetStreamSourceFreq
,
8054 IWineD3DDeviceImpl_GetStreamSourceFreq
,
8055 IWineD3DDeviceImpl_SetTexture
,
8056 IWineD3DDeviceImpl_GetTexture
,
8057 IWineD3DDeviceImpl_SetTextureStageState
,
8058 IWineD3DDeviceImpl_GetTextureStageState
,
8059 IWineD3DDeviceImpl_SetTransform
,
8060 IWineD3DDeviceImpl_GetTransform
,
8061 IWineD3DDeviceImpl_SetVertexDeclaration
,
8062 IWineD3DDeviceImpl_GetVertexDeclaration
,
8063 IWineD3DDeviceImpl_SetVertexShader
,
8064 IWineD3DDeviceImpl_GetVertexShader
,
8065 IWineD3DDeviceImpl_SetVertexShaderConstantB
,
8066 IWineD3DDeviceImpl_GetVertexShaderConstantB
,
8067 IWineD3DDeviceImpl_SetVertexShaderConstantI
,
8068 IWineD3DDeviceImpl_GetVertexShaderConstantI
,
8069 IWineD3DDeviceImpl_SetVertexShaderConstantF
,
8070 IWineD3DDeviceImpl_GetVertexShaderConstantF
,
8071 IWineD3DDeviceImpl_SetViewport
,
8072 IWineD3DDeviceImpl_GetViewport
,
8073 IWineD3DDeviceImpl_MultiplyTransform
,
8074 IWineD3DDeviceImpl_ValidateDevice
,
8075 IWineD3DDeviceImpl_ProcessVertices
,
8076 /*** State block ***/
8077 IWineD3DDeviceImpl_BeginStateBlock
,
8078 IWineD3DDeviceImpl_EndStateBlock
,
8079 /*** Scene management ***/
8080 IWineD3DDeviceImpl_BeginScene
,
8081 IWineD3DDeviceImpl_EndScene
,
8082 IWineD3DDeviceImpl_Present
,
8083 IWineD3DDeviceImpl_Clear
,
8084 IWineD3DDeviceImpl_ClearRendertargetView
,
8086 IWineD3DDeviceImpl_SetPrimitiveType
,
8087 IWineD3DDeviceImpl_GetPrimitiveType
,
8088 IWineD3DDeviceImpl_DrawPrimitive
,
8089 IWineD3DDeviceImpl_DrawIndexedPrimitive
,
8090 IWineD3DDeviceImpl_DrawPrimitiveUP
,
8091 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP
,
8092 IWineD3DDeviceImpl_DrawPrimitiveStrided
,
8093 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided
,
8094 IWineD3DDeviceImpl_DrawRectPatch
,
8095 IWineD3DDeviceImpl_DrawTriPatch
,
8096 IWineD3DDeviceImpl_DeletePatch
,
8097 IWineD3DDeviceImpl_ColorFill
,
8098 IWineD3DDeviceImpl_UpdateTexture
,
8099 IWineD3DDeviceImpl_UpdateSurface
,
8100 IWineD3DDeviceImpl_GetFrontBufferData
,
8101 /*** object tracking ***/
8102 IWineD3DDeviceImpl_ResourceReleased
,
8103 IWineD3DDeviceImpl_EnumResources
8106 const DWORD SavedPixelStates_R
[NUM_SAVEDPIXELSTATES_R
] = {
8107 WINED3DRS_ALPHABLENDENABLE
,
8108 WINED3DRS_ALPHAFUNC
,
8109 WINED3DRS_ALPHAREF
,
8110 WINED3DRS_ALPHATESTENABLE
,
8112 WINED3DRS_COLORWRITEENABLE
,
8113 WINED3DRS_DESTBLEND
,
8114 WINED3DRS_DITHERENABLE
,
8115 WINED3DRS_FILLMODE
,
8116 WINED3DRS_FOGDENSITY
,
8118 WINED3DRS_FOGSTART
,
8119 WINED3DRS_LASTPIXEL
,
8120 WINED3DRS_SHADEMODE
,
8121 WINED3DRS_SRCBLEND
,
8122 WINED3DRS_STENCILENABLE
,
8123 WINED3DRS_STENCILFAIL
,
8124 WINED3DRS_STENCILFUNC
,
8125 WINED3DRS_STENCILMASK
,
8126 WINED3DRS_STENCILPASS
,
8127 WINED3DRS_STENCILREF
,
8128 WINED3DRS_STENCILWRITEMASK
,
8129 WINED3DRS_STENCILZFAIL
,
8130 WINED3DRS_TEXTUREFACTOR
,
8141 WINED3DRS_ZWRITEENABLE
8144 const DWORD SavedPixelStates_T
[NUM_SAVEDPIXELSTATES_T
] = {
8145 WINED3DTSS_ALPHAARG0
,
8146 WINED3DTSS_ALPHAARG1
,
8147 WINED3DTSS_ALPHAARG2
,
8148 WINED3DTSS_ALPHAOP
,
8149 WINED3DTSS_BUMPENVLOFFSET
,
8150 WINED3DTSS_BUMPENVLSCALE
,
8151 WINED3DTSS_BUMPENVMAT00
,
8152 WINED3DTSS_BUMPENVMAT01
,
8153 WINED3DTSS_BUMPENVMAT10
,
8154 WINED3DTSS_BUMPENVMAT11
,
8155 WINED3DTSS_COLORARG0
,
8156 WINED3DTSS_COLORARG1
,
8157 WINED3DTSS_COLORARG2
,
8158 WINED3DTSS_COLOROP
,
8159 WINED3DTSS_RESULTARG
,
8160 WINED3DTSS_TEXCOORDINDEX
,
8161 WINED3DTSS_TEXTURETRANSFORMFLAGS
8164 const DWORD SavedPixelStates_S
[NUM_SAVEDPIXELSTATES_S
] = {
8165 WINED3DSAMP_ADDRESSU
,
8166 WINED3DSAMP_ADDRESSV
,
8167 WINED3DSAMP_ADDRESSW
,
8168 WINED3DSAMP_BORDERCOLOR
,
8169 WINED3DSAMP_MAGFILTER
,
8170 WINED3DSAMP_MINFILTER
,
8171 WINED3DSAMP_MIPFILTER
,
8172 WINED3DSAMP_MIPMAPLODBIAS
,
8173 WINED3DSAMP_MAXMIPLEVEL
,
8174 WINED3DSAMP_MAXANISOTROPY
,
8175 WINED3DSAMP_SRGBTEXTURE
,
8176 WINED3DSAMP_ELEMENTINDEX
8179 const DWORD SavedVertexStates_R
[NUM_SAVEDVERTEXSTATES_R
] = {
8181 WINED3DRS_AMBIENTMATERIALSOURCE
,
8182 WINED3DRS_CLIPPING
,
8183 WINED3DRS_CLIPPLANEENABLE
,
8184 WINED3DRS_COLORVERTEX
,
8185 WINED3DRS_DIFFUSEMATERIALSOURCE
,
8186 WINED3DRS_EMISSIVEMATERIALSOURCE
,
8187 WINED3DRS_FOGDENSITY
,
8189 WINED3DRS_FOGSTART
,
8190 WINED3DRS_FOGTABLEMODE
,
8191 WINED3DRS_FOGVERTEXMODE
,
8192 WINED3DRS_INDEXEDVERTEXBLENDENABLE
,
8193 WINED3DRS_LIGHTING
,
8194 WINED3DRS_LOCALVIEWER
,
8195 WINED3DRS_MULTISAMPLEANTIALIAS
,
8196 WINED3DRS_MULTISAMPLEMASK
,
8197 WINED3DRS_NORMALIZENORMALS
,
8198 WINED3DRS_PATCHEDGESTYLE
,
8199 WINED3DRS_POINTSCALE_A
,
8200 WINED3DRS_POINTSCALE_B
,
8201 WINED3DRS_POINTSCALE_C
,
8202 WINED3DRS_POINTSCALEENABLE
,
8203 WINED3DRS_POINTSIZE
,
8204 WINED3DRS_POINTSIZE_MAX
,
8205 WINED3DRS_POINTSIZE_MIN
,
8206 WINED3DRS_POINTSPRITEENABLE
,
8207 WINED3DRS_RANGEFOGENABLE
,
8208 WINED3DRS_SPECULARMATERIALSOURCE
,
8209 WINED3DRS_TWEENFACTOR
,
8210 WINED3DRS_VERTEXBLEND
,
8211 WINED3DRS_CULLMODE
,
8215 const DWORD SavedVertexStates_T
[NUM_SAVEDVERTEXSTATES_T
] = {
8216 WINED3DTSS_TEXCOORDINDEX
,
8217 WINED3DTSS_TEXTURETRANSFORMFLAGS
8220 const DWORD SavedVertexStates_S
[NUM_SAVEDVERTEXSTATES_S
] = {
8221 WINED3DSAMP_DMAPOFFSET
8224 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl
*This
, DWORD state
) {
8225 DWORD rep
= This
->StateTable
[state
].representative
;
8229 WineD3DContext
*context
;
8232 for(i
= 0; i
< This
->numContexts
; i
++) {
8233 context
= This
->contexts
[i
];
8234 if(isStateDirty(context
, rep
)) continue;
8236 context
->dirtyArray
[context
->numDirtyEntries
++] = rep
;
8239 context
->isStateDirty
[idx
] |= (1 << shift
);
8243 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl
*This
, UINT
*width
, UINT
*height
) {
8244 IWineD3DDeviceImpl
*dev
= This
->resource
.wineD3DDevice
;
8245 /* The drawable size of a pbuffer render target is the current pbuffer size
8247 *width
= dev
->pbufferWidth
;
8248 *height
= dev
->pbufferHeight
;
8251 void get_drawable_size_fbo(IWineD3DSurfaceImpl
*This
, UINT
*width
, UINT
*height
) {
8252 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
8254 *width
= This
->pow2Width
;
8255 *height
= This
->pow2Height
;
8258 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl
*This
, UINT
*width
, UINT
*height
) {
8259 IWineD3DDeviceImpl
*dev
= This
->resource
.wineD3DDevice
;
8260 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
8261 * current context's drawable, which is the size of the back buffer of the swapchain
8262 * the active context belongs to. The back buffer of the swapchain is stored as the
8263 * surface the context belongs to.
8265 *width
= ((IWineD3DSurfaceImpl
*) dev
->activeContext
->surface
)->currentDesc
.Width
;
8266 *height
= ((IWineD3DSurfaceImpl
*) dev
->activeContext
->surface
)->currentDesc
.Height
;