2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
12 * Copyright 2009 Henri Verbeet for CodeWeavers
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
34 #include "wined3d_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
37 #define GLINFO_LOCATION This->adapter->gl_info
39 /* Define the default light parameters as specified by MSDN */
40 const WINED3DLIGHT WINED3D_default_light = {
42 WINED3DLIGHT_DIRECTIONAL, /* Type */
43 { 1.0f, 1.0f, 1.0f, 0.0f }, /* Diffuse r,g,b,a */
44 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Specular r,g,b,a */
45 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Ambient r,g,b,a, */
46 { 0.0f, 0.0f, 0.0f }, /* Position x,y,z */
47 { 0.0f, 0.0f, 1.0f }, /* Direction x,y,z */
50 0.0f, 0.0f, 0.0f, /* Attenuation 0,1,2 */
55 /**********************************************************
56 * Global variable / Constants follow
57 **********************************************************/
58 const float identity[] =
60 1.0f, 0.0f, 0.0f, 0.0f,
61 0.0f, 1.0f, 0.0f, 0.0f,
62 0.0f, 0.0f, 1.0f, 0.0f,
63 0.0f, 0.0f, 0.0f, 1.0f,
64 }; /* When needed for comparisons */
66 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
67 * actually have the same values in GL and D3D. */
68 static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
70 switch(primitive_type)
72 case WINED3DPT_POINTLIST:
75 case WINED3DPT_LINELIST:
78 case WINED3DPT_LINESTRIP:
81 case WINED3DPT_TRIANGLELIST:
84 case WINED3DPT_TRIANGLESTRIP:
85 return GL_TRIANGLE_STRIP;
87 case WINED3DPT_TRIANGLEFAN:
88 return GL_TRIANGLE_FAN;
90 case WINED3DPT_LINELIST_ADJ:
91 return GL_LINES_ADJACENCY_ARB;
93 case WINED3DPT_LINESTRIP_ADJ:
94 return GL_LINE_STRIP_ADJACENCY_ARB;
96 case WINED3DPT_TRIANGLELIST_ADJ:
97 return GL_TRIANGLES_ADJACENCY_ARB;
99 case WINED3DPT_TRIANGLESTRIP_ADJ:
100 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
103 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
108 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
110 switch(primitive_type)
113 return WINED3DPT_POINTLIST;
116 return WINED3DPT_LINELIST;
119 return WINED3DPT_LINESTRIP;
122 return WINED3DPT_TRIANGLELIST;
124 case GL_TRIANGLE_STRIP:
125 return WINED3DPT_TRIANGLESTRIP;
127 case GL_TRIANGLE_FAN:
128 return WINED3DPT_TRIANGLEFAN;
130 case GL_LINES_ADJACENCY_ARB:
131 return WINED3DPT_LINELIST_ADJ;
133 case GL_LINE_STRIP_ADJACENCY_ARB:
134 return WINED3DPT_LINESTRIP_ADJ;
136 case GL_TRIANGLES_ADJACENCY_ARB:
137 return WINED3DPT_TRIANGLELIST_ADJ;
139 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
140 return WINED3DPT_TRIANGLESTRIP_ADJ;
143 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
144 return WINED3DPT_UNDEFINED;
148 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
150 if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && usage_idx == 0)
151 *regnum = WINED3D_FFP_POSITION;
152 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
153 *regnum = WINED3D_FFP_BLENDWEIGHT;
154 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
155 *regnum = WINED3D_FFP_BLENDINDICES;
156 else if (usage == WINED3DDECLUSAGE_NORMAL && usage_idx == 0)
157 *regnum = WINED3D_FFP_NORMAL;
158 else if (usage == WINED3DDECLUSAGE_PSIZE && usage_idx == 0)
159 *regnum = WINED3D_FFP_PSIZE;
160 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 0)
161 *regnum = WINED3D_FFP_DIFFUSE;
162 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1)
163 *regnum = WINED3D_FFP_SPECULAR;
164 else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
165 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
168 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
176 /* Context activation is done by the caller. */
177 void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
178 BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
180 /* We need to deal with frequency data! */
181 IWineD3DVertexDeclarationImpl *declaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
182 UINT stream_count = This->stateBlock->streamIsUP ? 0 : declaration->num_streams;
183 const DWORD *streams = declaration->streams;
186 stream_info->use_map = 0;
187 stream_info->swizzle_map = 0;
189 /* Check for transformed vertices, disable vertex shader if present. */
190 stream_info->position_transformed = declaration->position_transformed;
191 if (declaration->position_transformed) use_vshader = FALSE;
193 /* Translate the declaration into strided data. */
194 for (i = 0; i < declaration->element_count; ++i)
196 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
197 GLuint buffer_object = 0;
198 const BYTE *data = NULL;
203 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
204 element, i + 1, declaration->element_count);
206 if (!This->stateBlock->streamSource[element->input_slot]) continue;
208 stride = This->stateBlock->streamStride[element->input_slot];
209 if (This->stateBlock->streamIsUP)
211 TRACE("Stream %u is UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
213 data = (BYTE *)This->stateBlock->streamSource[element->input_slot];
217 TRACE("Stream %u isn't UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
218 data = buffer_get_memory(This->stateBlock->streamSource[element->input_slot], 0, &buffer_object);
220 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
221 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
222 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
223 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
224 * not, drawStridedSlow is needed, including a vertex buffer path. */
225 if (This->stateBlock->loadBaseVertexIndex < 0)
227 WARN("loadBaseVertexIndex is < 0 (%d), not using vbos\n", This->stateBlock->loadBaseVertexIndex);
229 data = buffer_get_sysmem((struct wined3d_buffer *)This->stateBlock->streamSource[element->input_slot]);
230 if ((UINT_PTR)data < -This->stateBlock->loadBaseVertexIndex * stride)
232 FIXME("System memory vertex data load offset is negative!\n");
238 if (buffer_object) *fixup = TRUE;
239 else if (*fixup && !use_vshader
240 && (element->usage == WINED3DDECLUSAGE_COLOR
241 || element->usage == WINED3DDECLUSAGE_POSITIONT))
243 static BOOL warned = FALSE;
246 /* This may be bad with the fixed function pipeline. */
247 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
253 data += element->offset;
255 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
259 if (element->output_slot == ~0U)
261 /* TODO: Assuming vertexdeclarations are usually used with the
262 * same or a similar shader, it might be worth it to store the
263 * last used output slot and try that one first. */
264 stride_used = vshader_get_input(This->stateBlock->vertexShader,
265 element->usage, element->usage_idx, &idx);
269 idx = element->output_slot;
275 if (!element->ffp_valid)
277 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
278 debug_d3dformat(element->format_desc->format), debug_d3ddeclusage(element->usage));
283 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
289 TRACE("Load %s array %u [usage %s, usage_idx %u, "
290 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
291 use_vshader ? "shader": "fixed function", idx,
292 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
293 element->offset, stride, debug_d3dformat(element->format_desc->format), buffer_object);
295 stream_info->elements[idx].format_desc = element->format_desc;
296 stream_info->elements[idx].stride = stride;
297 stream_info->elements[idx].data = data;
298 stream_info->elements[idx].stream_idx = element->input_slot;
299 stream_info->elements[idx].buffer_object = buffer_object;
301 if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA) && element->format_desc->format == WINED3DFMT_A8R8G8B8)
303 stream_info->swizzle_map |= 1 << idx;
305 stream_info->use_map |= 1 << idx;
309 /* Now call PreLoad on all the vertex buffers. In the very rare case
310 * that the buffers stopps converting PreLoad will dirtify the VDECL again.
311 * The vertex buffer can now use the strided structure in the device instead of finding its
314 * NULL streams won't be recorded in the array, UP streams won't be either. A stream is only
316 for (i = 0; i < stream_count; ++i)
318 IWineD3DBuffer *vb = This->stateBlock->streamSource[streams[i]];
319 if (vb) IWineD3DBuffer_PreLoad(vb);
323 static void stream_info_element_from_strided(IWineD3DDeviceImpl *This,
324 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
326 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(strided->format, &This->adapter->gl_info);
327 e->format_desc = format_desc;
328 e->stride = strided->dwStride;
329 e->data = strided->lpData;
331 e->buffer_object = 0;
334 void device_stream_info_from_strided(IWineD3DDeviceImpl *This,
335 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
339 memset(stream_info, 0, sizeof(*stream_info));
341 if (strided->position.lpData)
342 stream_info_element_from_strided(This, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
343 if (strided->normal.lpData)
344 stream_info_element_from_strided(This, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
345 if (strided->diffuse.lpData)
346 stream_info_element_from_strided(This, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
347 if (strided->specular.lpData)
348 stream_info_element_from_strided(This, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
350 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
352 if (strided->texCoords[i].lpData)
353 stream_info_element_from_strided(This, &strided->texCoords[i],
354 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
357 stream_info->position_transformed = strided->position_transformed;
359 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
361 if (!stream_info->elements[i].format_desc) continue;
363 if (!GL_SUPPORT(EXT_VERTEX_ARRAY_BGRA) && stream_info->elements[i].format_desc->format == WINED3DFMT_A8R8G8B8)
365 stream_info->swizzle_map |= 1 << i;
367 stream_info->use_map |= 1 << i;
371 /**********************************************************
372 * IUnknown parts follows
373 **********************************************************/
375 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
377 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
379 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
380 if (IsEqualGUID(riid, &IID_IUnknown)
381 || IsEqualGUID(riid, &IID_IWineD3DBase)
382 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
383 IUnknown_AddRef(iface);
388 return E_NOINTERFACE;
391 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
392 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
393 ULONG refCount = InterlockedIncrement(&This->ref);
395 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
399 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
400 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
401 ULONG refCount = InterlockedDecrement(&This->ref);
403 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
408 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
409 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
410 This->multistate_funcs[i] = NULL;
413 /* TODO: Clean up all the surfaces and textures! */
414 /* NOTE: You must release the parent if the object was created via a callback
415 ** ***************************/
417 if (!list_empty(&This->resources)) {
418 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
419 dumpResources(&This->resources);
422 if(This->contexts) ERR("Context array not freed!\n");
423 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
424 This->haveHardwareCursor = FALSE;
426 IWineD3D_Release(This->wineD3D);
427 This->wineD3D = NULL;
428 HeapFree(GetProcessHeap(), 0, This);
429 TRACE("Freed device %p\n", This);
435 /**********************************************************
436 * IWineD3DDevice implementation follows
437 **********************************************************/
438 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
439 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
440 *pParent = This->parent;
441 IUnknown_AddRef(This->parent);
445 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
446 const void *data, IUnknown *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
448 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
449 struct wined3d_buffer *object;
452 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
454 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
457 ERR("Failed to allocate memory\n");
458 return E_OUTOFMEMORY;
461 FIXME("Ignoring access flags (pool)\n");
463 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
464 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
467 WARN("Failed to initialize buffer, hr %#x.\n", hr);
468 HeapFree(GetProcessHeap(), 0, object);
471 object->desc = *desc;
473 TRACE("Created buffer %p.\n", object);
475 *buffer = (IWineD3DBuffer *)object;
480 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size,
481 DWORD Usage, DWORD FVF, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer,
482 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
484 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
485 struct wined3d_buffer *object;
486 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
490 if (Pool == WINED3DPOOL_SCRATCH)
492 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
493 * anyway, SCRATCH vertex buffers aren't usable anywhere
495 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
496 *ppVertexBuffer = NULL;
497 return WINED3DERR_INVALIDCALL;
500 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
503 ERR("Out of memory\n");
504 *ppVertexBuffer = NULL;
505 return WINED3DERR_OUTOFVIDEOMEMORY;
508 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
509 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
512 WARN("Failed to initialize buffer, hr %#x.\n", hr);
513 HeapFree(GetProcessHeap(), 0, object);
517 TRACE("Created buffer %p.\n", object);
518 TRACE("FVF %#x, Pool %#x.\n", FVF, Pool);
519 *ppVertexBuffer = (IWineD3DBuffer *)object;
521 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
522 * drawStridedFast (half-life 2).
524 * Basically converting the vertices in the buffer is quite expensive, and observations
525 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
526 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
528 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
529 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
530 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
531 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
533 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
534 * more. In this call we can convert dx7 buffers too.
536 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
537 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
538 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
539 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
540 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
541 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
542 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
543 } else if(dxVersion <= 7 && conv) {
544 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
546 object->flags |= WINED3D_BUFFER_CREATEBO;
551 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
552 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer,
553 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
555 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
556 struct wined3d_buffer *object;
559 TRACE("(%p) Creating index buffer\n", This);
561 /* Allocate the storage for the device */
562 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
565 ERR("Out of memory\n");
566 *ppIndexBuffer = NULL;
567 return WINED3DERR_OUTOFVIDEOMEMORY;
570 hr = buffer_init(object, This, Length, Usage, WINED3DFMT_UNKNOWN,
571 Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
574 WARN("Failed to initialize buffer, hr %#x\n", hr);
575 HeapFree(GetProcessHeap(), 0, object);
579 TRACE("Created buffer %p.\n", object);
581 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
582 object->flags |= WINED3D_BUFFER_CREATEBO;
585 *ppIndexBuffer = (IWineD3DBuffer *) object;
590 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
592 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
593 IWineD3DStateBlockImpl *object;
597 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
600 ERR("Out of memory\n");
601 *ppStateBlock = NULL;
602 return WINED3DERR_OUTOFVIDEOMEMORY;
605 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
606 object->wineD3DDevice = This;
607 object->parent = parent;
609 object->blockType = Type;
611 *ppStateBlock = (IWineD3DStateBlock *)object;
613 for(i = 0; i < LIGHTMAP_SIZE; i++) {
614 list_init(&object->lightMap[i]);
617 temp_result = allocate_shader_constants(object);
618 if (FAILED(temp_result))
620 HeapFree(GetProcessHeap(), 0, object);
624 /* Special case - Used during initialization to produce a placeholder stateblock
625 so other functions called can update a state block */
626 if (Type == WINED3DSBT_INIT || Type == WINED3DSBT_RECORDED)
628 /* Don't bother increasing the reference count otherwise a device will never
629 be freed due to circular dependencies */
633 /* Otherwise, might as well set the whole state block to the appropriate values */
634 if (This->stateBlock != NULL)
635 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
637 memset(object->streamFreq, 1, sizeof(object->streamFreq));
639 /* Reset the ref and type after kludging it */
640 object->wineD3DDevice = This;
642 object->blockType = Type;
644 TRACE("Updating changed flags appropriate for type %d\n", Type);
646 if (Type == WINED3DSBT_ALL) {
648 TRACE("ALL => Pretend everything has changed\n");
649 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
651 /* Lights are not part of the changed / set structure */
652 for(j = 0; j < LIGHTMAP_SIZE; j++) {
654 LIST_FOR_EACH(e, &object->lightMap[j]) {
655 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
656 light->changed = TRUE;
657 light->enabledChanged = TRUE;
660 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
661 object->contained_render_states[j - 1] = j;
663 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
664 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
665 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
666 object->contained_transform_states[j - 1] = j;
668 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
669 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
670 object->contained_vs_consts_f[j] = j;
672 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
673 for(j = 0; j < MAX_CONST_I; j++) {
674 object->contained_vs_consts_i[j] = j;
676 object->num_contained_vs_consts_i = MAX_CONST_I;
677 for(j = 0; j < MAX_CONST_B; j++) {
678 object->contained_vs_consts_b[j] = j;
680 object->num_contained_vs_consts_b = MAX_CONST_B;
681 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
682 object->contained_ps_consts_f[j] = j;
684 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
685 for(j = 0; j < MAX_CONST_I; j++) {
686 object->contained_ps_consts_i[j] = j;
688 object->num_contained_ps_consts_i = MAX_CONST_I;
689 for(j = 0; j < MAX_CONST_B; j++) {
690 object->contained_ps_consts_b[j] = j;
692 object->num_contained_ps_consts_b = MAX_CONST_B;
693 for(i = 0; i < MAX_TEXTURES; i++) {
694 for (j = 0; j <= WINED3D_HIGHEST_TEXTURE_STATE; ++j)
696 object->contained_tss_states[object->num_contained_tss_states].stage = i;
697 object->contained_tss_states[object->num_contained_tss_states].state = j;
698 object->num_contained_tss_states++;
701 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
702 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
703 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
704 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
705 object->num_contained_sampler_states++;
709 for(i = 0; i < MAX_STREAMS; i++) {
710 if(object->streamSource[i]) {
711 IWineD3DBuffer_AddRef(object->streamSource[i]);
714 if(object->pIndexData) {
715 IWineD3DBuffer_AddRef(object->pIndexData);
717 if(object->vertexShader) {
718 IWineD3DVertexShader_AddRef(object->vertexShader);
720 if(object->pixelShader) {
721 IWineD3DPixelShader_AddRef(object->pixelShader);
724 } else if (Type == WINED3DSBT_PIXELSTATE) {
726 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
727 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
729 object->changed.pixelShader = TRUE;
731 /* Pixel Shader Constants */
732 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
733 object->contained_ps_consts_f[i] = i;
734 object->changed.pixelShaderConstantsF[i] = TRUE;
736 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
737 for (i = 0; i < MAX_CONST_B; ++i) {
738 object->contained_ps_consts_b[i] = i;
739 object->changed.pixelShaderConstantsB |= (1 << i);
741 object->num_contained_ps_consts_b = MAX_CONST_B;
742 for (i = 0; i < MAX_CONST_I; ++i) {
743 object->contained_ps_consts_i[i] = i;
744 object->changed.pixelShaderConstantsI |= (1 << i);
746 object->num_contained_ps_consts_i = MAX_CONST_I;
748 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
749 DWORD rs = SavedPixelStates_R[i];
750 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
751 object->contained_render_states[i] = rs;
753 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
754 for (j = 0; j < MAX_TEXTURES; j++) {
755 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
756 DWORD state = SavedPixelStates_T[i];
757 object->changed.textureState[j] |= 1 << state;
758 object->contained_tss_states[object->num_contained_tss_states].stage = j;
759 object->contained_tss_states[object->num_contained_tss_states].state = state;
760 object->num_contained_tss_states++;
763 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
764 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
765 DWORD state = SavedPixelStates_S[i];
766 object->changed.samplerState[j] |= 1 << state;
767 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
768 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
769 object->num_contained_sampler_states++;
772 if(object->pixelShader) {
773 IWineD3DPixelShader_AddRef(object->pixelShader);
776 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
777 * on them. This makes releasing the buffer easier
779 for(i = 0; i < MAX_STREAMS; i++) {
780 object->streamSource[i] = NULL;
782 object->pIndexData = NULL;
783 object->vertexShader = NULL;
785 } else if (Type == WINED3DSBT_VERTEXSTATE) {
787 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
788 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
790 object->changed.vertexShader = TRUE;
792 /* Vertex Shader Constants */
793 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
794 object->changed.vertexShaderConstantsF[i] = TRUE;
795 object->contained_vs_consts_f[i] = i;
797 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
798 for (i = 0; i < MAX_CONST_B; ++i) {
799 object->contained_vs_consts_b[i] = i;
800 object->changed.vertexShaderConstantsB |= (1 << i);
802 object->num_contained_vs_consts_b = MAX_CONST_B;
803 for (i = 0; i < MAX_CONST_I; ++i) {
804 object->contained_vs_consts_i[i] = i;
805 object->changed.vertexShaderConstantsI |= (1 << i);
807 object->num_contained_vs_consts_i = MAX_CONST_I;
808 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
809 DWORD rs = SavedVertexStates_R[i];
810 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
811 object->contained_render_states[i] = rs;
813 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
814 for (j = 0; j < MAX_TEXTURES; j++) {
815 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
816 DWORD state = SavedVertexStates_T[i];
817 object->changed.textureState[j] |= 1 << state;
818 object->contained_tss_states[object->num_contained_tss_states].stage = j;
819 object->contained_tss_states[object->num_contained_tss_states].state = state;
820 object->num_contained_tss_states++;
823 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
824 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
825 DWORD state = SavedVertexStates_S[i];
826 object->changed.samplerState[j] |= 1 << state;
827 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
828 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
829 object->num_contained_sampler_states++;
833 for(j = 0; j < LIGHTMAP_SIZE; j++) {
835 LIST_FOR_EACH(e, &object->lightMap[j]) {
836 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
837 light->changed = TRUE;
838 light->enabledChanged = TRUE;
842 for(i = 0; i < MAX_STREAMS; i++) {
843 if(object->streamSource[i]) {
844 IWineD3DBuffer_AddRef(object->streamSource[i]);
847 if(object->vertexShader) {
848 IWineD3DVertexShader_AddRef(object->vertexShader);
850 object->pIndexData = NULL;
851 object->pixelShader = NULL;
853 FIXME("Unrecognized state block type %d\n", Type);
856 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
860 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
861 WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,
862 DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
863 WINED3DSURFTYPE Impl, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
865 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
866 IWineD3DSurfaceImpl *object;
869 TRACE("(%p) Create surface\n",This);
871 if (Impl == SURFACE_OPENGL && !This->adapter)
873 ERR("OpenGL surfaces are not available without OpenGL.\n");
874 return WINED3DERR_NOTAVAILABLE;
877 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
880 ERR("Failed to allocate surface memory.\n");
882 return WINED3DERR_OUTOFVIDEOMEMORY;
885 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
886 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
889 WARN("Failed to initialize surface, returning %#x.\n", hr);
890 HeapFree(GetProcessHeap(), 0, object);
895 TRACE("(%p) : Created surface %p\n", This, object);
897 *ppSurface = (IWineD3DSurface *)object;
902 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
903 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
905 struct wined3d_rendertarget_view *object;
907 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
910 ERR("Failed to allocate memory\n");
911 return E_OUTOFMEMORY;
914 object->vtbl = &wined3d_rendertarget_view_vtbl;
915 object->refcount = 1;
916 IWineD3DResource_AddRef(resource);
917 object->resource = resource;
918 object->parent = parent;
920 *rendertarget_view = (IWineD3DRendertargetView *)object;
925 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
926 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
927 IWineD3DTexture **ppTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
929 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
930 IWineD3DTextureImpl *object;
933 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
934 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
935 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
937 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
940 ERR("Out of memory\n");
942 return WINED3DERR_OUTOFVIDEOMEMORY;
945 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
948 WARN("Failed to initialize texture, returning %#x\n", hr);
949 HeapFree(GetProcessHeap(), 0, object);
954 *ppTexture = (IWineD3DTexture *)object;
956 TRACE("(%p) : Created texture %p\n", This, object);
961 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
962 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
963 IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
965 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
966 IWineD3DVolumeTextureImpl *object;
969 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
970 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
972 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
975 ERR("Out of memory\n");
976 *ppVolumeTexture = NULL;
977 return WINED3DERR_OUTOFVIDEOMEMORY;
980 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
983 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
984 HeapFree(GetProcessHeap(), 0, object);
985 *ppVolumeTexture = NULL;
989 TRACE("(%p) : Created volume texture %p.\n", This, object);
990 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
995 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
996 UINT Depth, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DVolume **ppVolume,
997 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
999 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1000 IWineD3DVolumeImpl *object;
1003 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1004 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1006 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1009 ERR("Out of memory\n");
1011 return WINED3DERR_OUTOFVIDEOMEMORY;
1014 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
1017 WARN("Failed to initialize volume, returning %#x.\n", hr);
1018 HeapFree(GetProcessHeap(), 0, object);
1022 TRACE("(%p) : Created volume %p.\n", This, object);
1023 *ppVolume = (IWineD3DVolume *)object;
1028 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
1029 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture,
1030 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
1032 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1033 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1036 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1039 ERR("Out of memory\n");
1040 *ppCubeTexture = NULL;
1041 return WINED3DERR_OUTOFVIDEOMEMORY;
1044 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
1047 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1048 HeapFree(GetProcessHeap(), 0, object);
1049 *ppCubeTexture = NULL;
1053 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1054 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1059 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1060 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1061 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1062 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1063 const IWineD3DQueryVtbl *vtable;
1065 /* Just a check to see if we support this type of query */
1067 case WINED3DQUERYTYPE_OCCLUSION:
1068 TRACE("(%p) occlusion query\n", This);
1069 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1072 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1074 vtable = &IWineD3DOcclusionQuery_Vtbl;
1077 case WINED3DQUERYTYPE_EVENT:
1078 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1079 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1080 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1082 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1084 vtable = &IWineD3DEventQuery_Vtbl;
1088 case WINED3DQUERYTYPE_VCACHE:
1089 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1090 case WINED3DQUERYTYPE_VERTEXSTATS:
1091 case WINED3DQUERYTYPE_TIMESTAMP:
1092 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1093 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1094 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1095 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1096 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1097 case WINED3DQUERYTYPE_PIXELTIMINGS:
1098 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1099 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1101 /* Use the base Query vtable until we have a special one for each query */
1102 vtable = &IWineD3DQuery_Vtbl;
1103 FIXME("(%p) Unhandled query type %d\n", This, Type);
1105 if(NULL == ppQuery || hr != WINED3D_OK) {
1109 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1112 ERR("Out of memory\n");
1114 return WINED3DERR_OUTOFVIDEOMEMORY;
1117 object->lpVtbl = vtable;
1118 object->type = Type;
1119 object->state = QUERY_CREATED;
1120 object->wineD3DDevice = This;
1121 object->parent = parent;
1124 *ppQuery = (IWineD3DQuery *)object;
1126 /* allocated the 'extended' data based on the type of query requested */
1128 case WINED3DQUERYTYPE_OCCLUSION:
1129 object->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_occlusion_query));
1130 ((struct wined3d_occlusion_query *)object->extendedData)->context = NULL;
1133 case WINED3DQUERYTYPE_EVENT:
1134 object->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_event_query));
1135 ((struct wined3d_event_query *)object->extendedData)->context = NULL;
1138 case WINED3DQUERYTYPE_VCACHE:
1139 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1140 case WINED3DQUERYTYPE_VERTEXSTATS:
1141 case WINED3DQUERYTYPE_TIMESTAMP:
1142 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1143 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1144 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1145 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1146 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1147 case WINED3DQUERYTYPE_PIXELTIMINGS:
1148 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1149 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1151 object->extendedData = 0;
1152 FIXME("(%p) Unhandled query type %d\n",This , Type);
1154 TRACE("(%p) : Created Query %p\n", This, object);
1158 /*****************************************************************************
1159 * IWineD3DDeviceImpl_SetupFullscreenWindow
1161 * Helper function that modifies a HWND's Style and ExStyle for proper
1165 * iface: Pointer to the IWineD3DDevice interface
1166 * window: Window to setup
1168 *****************************************************************************/
1169 static LONG fullscreen_style(LONG orig_style) {
1170 LONG style = orig_style;
1171 style &= ~WS_CAPTION;
1172 style &= ~WS_THICKFRAME;
1174 /* Make sure the window is managed, otherwise we won't get keyboard input */
1175 style |= WS_POPUP | WS_SYSMENU;
1180 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1181 LONG exStyle = orig_exStyle;
1183 /* Filter out window decorations */
1184 exStyle &= ~WS_EX_WINDOWEDGE;
1185 exStyle &= ~WS_EX_CLIENTEDGE;
1190 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1191 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1193 LONG style, exStyle;
1194 /* Don't do anything if an original style is stored.
1195 * That shouldn't happen
1197 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1198 if (This->style || This->exStyle) {
1199 ERR("(%p): Want to change the window parameters of HWND %p, but "
1200 "another style is stored for restoration afterwards\n", This, window);
1203 /* Get the parameters and save them */
1204 style = GetWindowLongW(window, GWL_STYLE);
1205 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1206 This->style = style;
1207 This->exStyle = exStyle;
1209 style = fullscreen_style(style);
1210 exStyle = fullscreen_exStyle(exStyle);
1212 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1213 This->style, This->exStyle, style, exStyle);
1215 SetWindowLongW(window, GWL_STYLE, style);
1216 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1218 /* Inform the window about the update. */
1219 SetWindowPos(window, HWND_TOP, 0, 0,
1220 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1223 /*****************************************************************************
1224 * IWineD3DDeviceImpl_RestoreWindow
1226 * Helper function that restores a windows' properties when taking it out
1227 * of fullscreen mode
1230 * iface: Pointer to the IWineD3DDevice interface
1231 * window: Window to setup
1233 *****************************************************************************/
1234 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1235 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1236 LONG style, exStyle;
1238 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1239 * switch, do nothing
1241 if (!This->style && !This->exStyle) return;
1243 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1244 This, window, This->style, This->exStyle);
1246 style = GetWindowLongW(window, GWL_STYLE);
1247 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1249 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1250 * Some applications change it before calling Reset() when switching between windowed and
1251 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1253 if(style == fullscreen_style(This->style) &&
1254 exStyle == fullscreen_style(This->exStyle)) {
1255 SetWindowLongW(window, GWL_STYLE, This->style);
1256 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1259 /* Delete the old values */
1263 /* Inform the window about the update */
1264 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1265 0, 0, 0, 0, /* Pos, Size, ignored */
1266 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1269 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1270 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1271 WINED3DPRESENT_PARAMETERS *pPresentationParameters, IWineD3DSwapChain **ppSwapChain,
1272 IUnknown *parent, WINED3DSURFTYPE surface_type)
1274 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1277 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1279 BOOL displaymode_set = FALSE;
1280 WINED3DDISPLAYMODE Mode;
1281 const struct GlPixelFormatDesc *format_desc;
1283 TRACE("(%p) : Created Additional Swap Chain\n", This);
1285 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1286 * does a device hold a reference to a swap chain giving them a lifetime of the device
1287 * or does the swap chain notify the device of its destruction.
1288 *******************************/
1290 /* Check the params */
1291 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1292 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1293 return WINED3DERR_INVALIDCALL;
1294 } else if (pPresentationParameters->BackBufferCount > 1) {
1295 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");
1298 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1301 ERR("Out of memory\n");
1302 *ppSwapChain = NULL;
1303 return WINED3DERR_OUTOFVIDEOMEMORY;
1306 switch(surface_type) {
1308 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1310 case SURFACE_OPENGL:
1311 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1313 case SURFACE_UNKNOWN:
1314 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1315 HeapFree(GetProcessHeap(), 0, object);
1316 return WINED3DERR_INVALIDCALL;
1318 object->wineD3DDevice = This;
1319 object->parent = parent;
1322 *ppSwapChain = (IWineD3DSwapChain *)object;
1324 /*********************
1325 * Lookup the window Handle and the relating X window handle
1326 ********************/
1328 /* Setup hwnd we are using, plus which display this equates to */
1329 object->win_handle = pPresentationParameters->hDeviceWindow;
1330 if (!object->win_handle) {
1331 object->win_handle = This->createParms.hFocusWindow;
1333 if(!pPresentationParameters->Windowed && object->win_handle) {
1334 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1335 pPresentationParameters->BackBufferWidth,
1336 pPresentationParameters->BackBufferHeight);
1339 hDc = GetDC(object->win_handle);
1340 TRACE("Using hDc %p\n", hDc);
1343 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1344 return WINED3DERR_NOTAVAILABLE;
1347 /* Get info on the current display setup */
1348 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1349 object->orig_width = Mode.Width;
1350 object->orig_height = Mode.Height;
1351 object->orig_fmt = Mode.Format;
1352 format_desc = getFormatDescEntry(Mode.Format, &GLINFO_LOCATION);
1354 if (pPresentationParameters->Windowed &&
1355 ((pPresentationParameters->BackBufferWidth == 0) ||
1356 (pPresentationParameters->BackBufferHeight == 0) ||
1357 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1360 GetClientRect(object->win_handle, &Rect);
1362 if (pPresentationParameters->BackBufferWidth == 0) {
1363 pPresentationParameters->BackBufferWidth = Rect.right;
1364 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1366 if (pPresentationParameters->BackBufferHeight == 0) {
1367 pPresentationParameters->BackBufferHeight = Rect.bottom;
1368 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1370 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1371 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1372 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1376 /* Put the correct figures in the presentation parameters */
1377 TRACE("Copying across presentation parameters\n");
1378 object->presentParms = *pPresentationParameters;
1380 TRACE("calling rendertarget CB\n");
1381 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1382 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1383 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1384 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->frontBuffer);
1385 if (SUCCEEDED(hr)) {
1386 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1387 ((IWineD3DSurfaceImpl *)object->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
1388 if(surface_type == SURFACE_OPENGL) {
1389 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1392 ERR("Failed to create the front buffer\n");
1396 /*********************
1397 * Windowed / Fullscreen
1398 *******************/
1401 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1402 * so we should really check to see if there is a fullscreen swapchain already
1403 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1404 **************************************/
1406 if (!pPresentationParameters->Windowed) {
1407 WINED3DDISPLAYMODE mode;
1410 /* Change the display settings */
1411 mode.Width = pPresentationParameters->BackBufferWidth;
1412 mode.Height = pPresentationParameters->BackBufferHeight;
1413 mode.Format = pPresentationParameters->BackBufferFormat;
1414 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1416 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1417 displaymode_set = TRUE;
1421 * Create an opengl context for the display visual
1422 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1423 * use different properties after that point in time. FIXME: How to handle when requested format
1424 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1425 * it chooses is identical to the one already being used!
1426 **********************************/
1427 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1429 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1430 if(!object->context) {
1431 ERR("Failed to create the context array\n");
1435 object->num_contexts = 1;
1437 if(surface_type == SURFACE_OPENGL) {
1438 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1439 if (!object->context[0]) {
1440 ERR("Failed to create a new context\n");
1441 hr = WINED3DERR_NOTAVAILABLE;
1444 TRACE("Context created (HWND=%p, glContext=%p)\n",
1445 object->win_handle, object->context[0]->glCtx);
1449 /*********************
1450 * Create the back, front and stencil buffers
1451 *******************/
1452 if(object->presentParms.BackBufferCount > 0) {
1455 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1456 if(!object->backBuffer) {
1457 ERR("Out of memory\n");
1462 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1463 TRACE("calling rendertarget CB\n");
1464 hr = IWineD3DDeviceParent_CreateRenderTarget(This->device_parent, parent,
1465 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1466 object->presentParms.BackBufferFormat, object->presentParms.MultiSampleType,
1467 object->presentParms.MultiSampleQuality, TRUE /* Lockable */, &object->backBuffer[i]);
1469 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1470 ((IWineD3DSurfaceImpl *)object->backBuffer[i])->Flags |= SFLAG_SWAPCHAIN;
1472 ERR("Cannot create new back buffer\n");
1475 if(surface_type == SURFACE_OPENGL) {
1477 glDrawBuffer(GL_BACK);
1478 checkGLcall("glDrawBuffer(GL_BACK)");
1483 object->backBuffer = NULL;
1485 /* Single buffering - draw to front buffer */
1486 if(surface_type == SURFACE_OPENGL) {
1488 glDrawBuffer(GL_FRONT);
1489 checkGLcall("glDrawBuffer(GL_FRONT)");
1494 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1495 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1496 TRACE("Creating depth stencil buffer\n");
1497 if (This->auto_depth_stencil_buffer == NULL ) {
1498 hr = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent, parent,
1499 object->presentParms.BackBufferWidth, object->presentParms.BackBufferHeight,
1500 object->presentParms.AutoDepthStencilFormat, object->presentParms.MultiSampleType,
1501 object->presentParms.MultiSampleQuality, FALSE /* FIXME: Discard */,
1502 &This->auto_depth_stencil_buffer);
1503 if (SUCCEEDED(hr)) {
1504 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1506 ERR("Failed to create the auto depth stencil\n");
1512 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1514 TRACE("Created swapchain %p\n", object);
1515 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1519 if (displaymode_set) {
1523 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1526 /* Change the display settings */
1527 memset(&devmode, 0, sizeof(devmode));
1528 devmode.dmSize = sizeof(devmode);
1529 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1530 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1531 devmode.dmPelsWidth = object->orig_width;
1532 devmode.dmPelsHeight = object->orig_height;
1533 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1536 if (object->backBuffer) {
1538 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1539 if (object->backBuffer[i]) IWineD3DSurface_Release(object->backBuffer[i]);
1541 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1542 object->backBuffer = NULL;
1544 if(object->context && object->context[0])
1545 DestroyContext(This, object->context[0]);
1546 if (object->frontBuffer) IWineD3DSurface_Release(object->frontBuffer);
1547 HeapFree(GetProcessHeap(), 0, object);
1551 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1552 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1553 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1554 TRACE("(%p)\n", This);
1556 return This->NumberOfSwapChains;
1559 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1560 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1561 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1563 if(iSwapChain < This->NumberOfSwapChains) {
1564 *pSwapChain = This->swapchains[iSwapChain];
1565 IWineD3DSwapChain_AddRef(*pSwapChain);
1566 TRACE("(%p) returning %p\n", This, *pSwapChain);
1569 TRACE("Swapchain out of range\n");
1571 return WINED3DERR_INVALIDCALL;
1576 * Vertex Declaration
1578 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1579 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1580 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1581 IWineD3DVertexDeclarationImpl *object = NULL;
1582 HRESULT hr = WINED3D_OK;
1584 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1585 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1587 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1590 ERR("Out of memory\n");
1591 *ppVertexDeclaration = NULL;
1592 return WINED3DERR_OUTOFVIDEOMEMORY;
1595 object->lpVtbl = &IWineD3DVertexDeclaration_Vtbl;
1596 object->wineD3DDevice = This;
1597 object->parent = parent;
1600 *ppVertexDeclaration = (IWineD3DVertexDeclaration *)object;
1602 hr = vertexdeclaration_init(object, elements, element_count);
1605 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
1606 *ppVertexDeclaration = NULL;
1612 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1613 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1615 unsigned int idx, idx2;
1616 unsigned int offset;
1617 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1618 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1619 BOOL has_blend_idx = has_blend &&
1620 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1621 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1622 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1623 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1624 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1625 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1626 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1628 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1629 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1630 WINED3DVERTEXELEMENT *elements = NULL;
1633 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1634 if (has_blend_idx) num_blends--;
1636 /* Compute declaration size */
1637 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1638 has_psize + has_diffuse + has_specular + num_textures;
1640 /* convert the declaration */
1641 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1642 if (!elements) return ~0U;
1646 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1647 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1648 elements[idx].usage = WINED3DDECLUSAGE_POSITIONT;
1650 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1651 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1652 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1655 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1656 elements[idx].usage = WINED3DDECLUSAGE_POSITION;
1658 elements[idx].usage_idx = 0;
1661 if (has_blend && (num_blends > 0)) {
1662 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1663 elements[idx].format = WINED3DFMT_A8R8G8B8;
1665 switch(num_blends) {
1666 case 1: elements[idx].format = WINED3DFMT_R32_FLOAT; break;
1667 case 2: elements[idx].format = WINED3DFMT_R32G32_FLOAT; break;
1668 case 3: elements[idx].format = WINED3DFMT_R32G32B32_FLOAT; break;
1669 case 4: elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
1671 ERR("Unexpected amount of blend values: %u\n", num_blends);
1674 elements[idx].usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1675 elements[idx].usage_idx = 0;
1678 if (has_blend_idx) {
1679 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1680 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1681 elements[idx].format = WINED3DFMT_R8G8B8A8_UINT;
1682 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1683 elements[idx].format = WINED3DFMT_A8R8G8B8;
1685 elements[idx].format = WINED3DFMT_R32_FLOAT;
1686 elements[idx].usage = WINED3DDECLUSAGE_BLENDINDICES;
1687 elements[idx].usage_idx = 0;
1691 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1692 elements[idx].usage = WINED3DDECLUSAGE_NORMAL;
1693 elements[idx].usage_idx = 0;
1697 elements[idx].format = WINED3DFMT_R32_FLOAT;
1698 elements[idx].usage = WINED3DDECLUSAGE_PSIZE;
1699 elements[idx].usage_idx = 0;
1703 elements[idx].format = WINED3DFMT_A8R8G8B8;
1704 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1705 elements[idx].usage_idx = 0;
1709 elements[idx].format = WINED3DFMT_A8R8G8B8;
1710 elements[idx].usage = WINED3DDECLUSAGE_COLOR;
1711 elements[idx].usage_idx = 1;
1714 for (idx2 = 0; idx2 < num_textures; idx2++) {
1715 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1716 switch (numcoords) {
1717 case WINED3DFVF_TEXTUREFORMAT1:
1718 elements[idx].format = WINED3DFMT_R32_FLOAT;
1720 case WINED3DFVF_TEXTUREFORMAT2:
1721 elements[idx].format = WINED3DFMT_R32G32_FLOAT;
1723 case WINED3DFVF_TEXTUREFORMAT3:
1724 elements[idx].format = WINED3DFMT_R32G32B32_FLOAT;
1726 case WINED3DFVF_TEXTUREFORMAT4:
1727 elements[idx].format = WINED3DFMT_R32G32B32A32_FLOAT;
1730 elements[idx].usage = WINED3DDECLUSAGE_TEXCOORD;
1731 elements[idx].usage_idx = idx2;
1735 /* Now compute offsets, and initialize the rest of the fields */
1736 for (idx = 0, offset = 0; idx < size; ++idx)
1738 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(elements[idx].format, &This->adapter->gl_info);
1739 elements[idx].input_slot = 0;
1740 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1741 elements[idx].offset = offset;
1742 offset += format_desc->component_count * format_desc->component_size;
1745 *ppVertexElements = elements;
1749 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1750 WINED3DVERTEXELEMENT* elements = NULL;
1751 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1755 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1756 if (size == ~0U) return WINED3DERR_OUTOFVIDEOMEMORY;
1758 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1759 HeapFree(GetProcessHeap(), 0, elements);
1760 if (hr != S_OK) return hr;
1765 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1766 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1767 IWineD3DVertexShader **ppVertexShader, IUnknown *parent)
1769 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1770 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1771 HRESULT hr = WINED3D_OK;
1773 if (!pFunction) return WINED3DERR_INVALIDCALL;
1775 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1778 ERR("Out of memory\n");
1779 *ppVertexShader = NULL;
1780 return WINED3DERR_OUTOFVIDEOMEMORY;
1783 object->lpVtbl = &IWineD3DVertexShader_Vtbl;
1784 object->parent = parent;
1785 shader_init(&object->baseShader, iface);
1786 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1787 *ppVertexShader = (IWineD3DVertexShader *)object;
1789 TRACE("(%p) : Created vertex shader %p\n", This, *ppVertexShader);
1791 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction, output_signature);
1794 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
1795 IWineD3DVertexShader_Release(*ppVertexShader);
1796 *ppVertexShader = NULL;
1803 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1804 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1805 IWineD3DPixelShader **ppPixelShader, IUnknown *parent)
1807 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1808 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1809 HRESULT hr = WINED3D_OK;
1811 if (!pFunction) return WINED3DERR_INVALIDCALL;
1813 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1816 ERR("Out of memory\n");
1817 *ppPixelShader = NULL;
1818 return WINED3DERR_OUTOFVIDEOMEMORY;
1821 object->lpVtbl = &IWineD3DPixelShader_Vtbl;
1822 object->parent = parent;
1823 shader_init(&object->baseShader, iface);
1824 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1825 *ppPixelShader = (IWineD3DPixelShader *)object;
1827 TRACE("(%p) : Created pixel shader %p\n", This, *ppPixelShader);
1829 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction, output_signature);
1832 WARN("(%p) : Failed to set function, returning %#x\n", iface, hr);
1833 IWineD3DPixelShader_Release(*ppPixelShader);
1834 *ppPixelShader = NULL;
1841 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1842 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1844 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1845 IWineD3DPaletteImpl *object;
1847 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1849 /* Create the new object */
1850 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1852 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1853 return E_OUTOFMEMORY;
1856 object->lpVtbl = &IWineD3DPalette_Vtbl;
1858 object->Flags = Flags;
1859 object->parent = Parent;
1860 object->wineD3DDevice = This;
1861 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1862 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1865 HeapFree( GetProcessHeap(), 0, object);
1866 return E_OUTOFMEMORY;
1869 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1871 IWineD3DPalette_Release((IWineD3DPalette *) object);
1875 *Palette = (IWineD3DPalette *) object;
1880 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1884 HDC dcb = NULL, dcs = NULL;
1885 WINEDDCOLORKEY colorkey;
1887 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1890 GetObjectA(hbm, sizeof(BITMAP), &bm);
1891 dcb = CreateCompatibleDC(NULL);
1893 SelectObject(dcb, hbm);
1897 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1898 * couldn't be loaded
1900 memset(&bm, 0, sizeof(bm));
1905 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5, TRUE,
1906 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1907 NULL, &wined3d_null_parent_ops);
1909 ERR("Wine logo requested, but failed to create surface\n");
1914 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1915 if(FAILED(hr)) goto out;
1916 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1917 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1919 colorkey.dwColorSpaceLowValue = 0;
1920 colorkey.dwColorSpaceHighValue = 0;
1921 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1923 /* Fill the surface with a white color to show that wined3d is there */
1924 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1937 /* Context activation is done by the caller. */
1938 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
1940 /* Under DirectX you can have texture stage operations even if no texture is
1941 bound, whereas opengl will only do texture operations when a valid texture is
1942 bound. We emulate this by creating dummy textures and binding them to each
1943 texture stage, but disable all stages by default. Hence if a stage is enabled
1944 then the default texture will kick in until replaced by a SetTexture call */
1947 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
1948 /* The dummy texture does not have client storage backing */
1949 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1950 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1952 for (i = 0; i < GL_LIMITS(textures); i++) {
1953 GLubyte white = 255;
1955 /* Make appropriate texture active */
1956 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1957 checkGLcall("glActiveTextureARB");
1959 /* Generate an opengl texture name */
1960 glGenTextures(1, &This->dummyTextureName[i]);
1961 checkGLcall("glGenTextures");
1962 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1964 /* Generate a dummy 2d texture (not using 1d because they cause many
1965 * DRI drivers fall back to sw) */
1966 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1967 checkGLcall("glBindTexture");
1969 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1970 checkGLcall("glTexImage2D");
1972 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
1973 /* Reenable because if supported it is enabled by default */
1974 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1975 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1981 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1982 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1984 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1985 IWineD3DSwapChainImpl *swapchain = NULL;
1990 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1992 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1993 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1995 /* TODO: Test if OpenGL is compiled in and loaded */
1997 TRACE("(%p) : Creating stateblock\n", This);
1998 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1999 hr = IWineD3DDevice_CreateStateBlock(iface,
2001 (IWineD3DStateBlock **)&This->stateBlock,
2003 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2004 WARN("Failed to create stateblock\n");
2007 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2008 This->updateStateBlock = This->stateBlock;
2009 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2011 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2012 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2014 This->NumberOfPalettes = 1;
2015 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2016 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2017 ERR("Out of memory!\n");
2020 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2021 if(!This->palettes[0]) {
2022 ERR("Out of memory!\n");
2025 for (i = 0; i < 256; ++i) {
2026 This->palettes[0][i].peRed = 0xFF;
2027 This->palettes[0][i].peGreen = 0xFF;
2028 This->palettes[0][i].peBlue = 0xFF;
2029 This->palettes[0][i].peFlags = 0xFF;
2031 This->currentPalette = 0;
2033 /* Initialize the texture unit mapping to a 1:1 mapping */
2034 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2035 if (state < GL_LIMITS(fragment_samplers)) {
2036 This->texUnitMap[state] = state;
2037 This->rev_tex_unit_map[state] = state;
2039 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
2040 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
2044 /* Setup the implicit swapchain. This also initializes a context. */
2045 TRACE("Creating implicit swapchain\n");
2046 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2047 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2050 WARN("Failed to create implicit swapchain\n");
2054 This->NumberOfSwapChains = 1;
2055 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2056 if(!This->swapchains) {
2057 ERR("Out of memory!\n");
2060 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2062 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2063 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2064 This->render_targets[0] = swapchain->backBuffer[0];
2067 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2068 This->render_targets[0] = swapchain->frontBuffer;
2070 IWineD3DSurface_AddRef(This->render_targets[0]);
2072 /* Depth Stencil support */
2073 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2074 if (NULL != This->stencilBufferTarget) {
2075 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2078 hr = This->shader_backend->shader_alloc_private(iface);
2080 TRACE("Shader private data couldn't be allocated\n");
2083 hr = This->frag_pipe->alloc_private(iface);
2085 TRACE("Fragment pipeline private data couldn't be allocated\n");
2088 hr = This->blitter->alloc_private(iface);
2090 TRACE("Blitter private data couldn't be allocated\n");
2094 /* Set up some starting GL setup */
2096 /* Setup all the devices defaults */
2097 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2098 create_dummy_textures(This);
2102 /* Initialize the current view state */
2103 This->view_ident = 1;
2104 This->contexts[0]->last_was_rhw = 0;
2105 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2106 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2108 switch(wined3d_settings.offscreen_rendering_mode) {
2111 This->offscreenBuffer = GL_BACK;
2114 case ORM_BACKBUFFER:
2116 if (context_get_current()->aux_buffers > 0)
2118 TRACE("Using auxilliary buffer for offscreen rendering\n");
2119 This->offscreenBuffer = GL_AUX0;
2121 TRACE("Using back buffer for offscreen rendering\n");
2122 This->offscreenBuffer = GL_BACK;
2127 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2130 /* Clear the screen */
2131 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2132 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2135 This->d3d_initialized = TRUE;
2137 if(wined3d_settings.logo) {
2138 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2140 This->highest_dirty_ps_const = 0;
2141 This->highest_dirty_vs_const = 0;
2145 HeapFree(GetProcessHeap(), 0, This->render_targets);
2146 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2147 HeapFree(GetProcessHeap(), 0, This->swapchains);
2148 This->NumberOfSwapChains = 0;
2149 if(This->palettes) {
2150 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2151 HeapFree(GetProcessHeap(), 0, This->palettes);
2153 This->NumberOfPalettes = 0;
2155 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2157 if(This->stateBlock) {
2158 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2159 This->stateBlock = NULL;
2161 if (This->blit_priv) {
2162 This->blitter->free_private(iface);
2164 if (This->fragment_priv) {
2165 This->frag_pipe->free_private(iface);
2167 if (This->shader_priv) {
2168 This->shader_backend->shader_free_private(iface);
2173 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
2174 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
2176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2177 IWineD3DSwapChainImpl *swapchain = NULL;
2180 /* Setup the implicit swapchain */
2181 TRACE("Creating implicit swapchain\n");
2182 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
2183 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2186 WARN("Failed to create implicit swapchain\n");
2190 This->NumberOfSwapChains = 1;
2191 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2192 if(!This->swapchains) {
2193 ERR("Out of memory!\n");
2196 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2200 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2204 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2206 IWineD3DResource_UnLoad(resource);
2207 IWineD3DResource_Release(resource);
2211 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
2212 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
2214 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2217 TRACE("(%p)\n", This);
2219 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2221 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2222 * it was created. Thus make sure a context is active for the glDelete* calls
2224 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
2226 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2228 /* Unload resources */
2229 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2231 TRACE("Deleting high order patches\n");
2232 for(i = 0; i < PATCHMAP_SIZE; i++) {
2233 struct list *e1, *e2;
2234 struct WineD3DRectPatch *patch;
2235 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2236 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2237 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2241 /* Delete the palette conversion shader if it is around */
2242 if(This->paletteConversionShader) {
2244 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2246 This->paletteConversionShader = 0;
2249 /* Delete the pbuffer context if there is any */
2250 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2252 /* Delete the mouse cursor texture */
2253 if(This->cursorTexture) {
2255 glDeleteTextures(1, &This->cursorTexture);
2257 This->cursorTexture = 0;
2260 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2261 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2263 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2264 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2267 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2268 * private data, it might contain opengl pointers
2270 if(This->depth_blt_texture) {
2272 glDeleteTextures(1, &This->depth_blt_texture);
2274 This->depth_blt_texture = 0;
2276 if (This->depth_blt_rb) {
2278 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2280 This->depth_blt_rb = 0;
2281 This->depth_blt_rb_w = 0;
2282 This->depth_blt_rb_h = 0;
2285 /* Release the update stateblock */
2286 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2287 if(This->updateStateBlock != This->stateBlock)
2288 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2290 This->updateStateBlock = NULL;
2292 { /* because were not doing proper internal refcounts releasing the primary state block
2293 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2294 to set this->stateBlock = NULL; first */
2295 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2296 This->stateBlock = NULL;
2298 /* Release the stateblock */
2299 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2300 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2304 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2305 This->blitter->free_private(iface);
2306 This->frag_pipe->free_private(iface);
2307 This->shader_backend->shader_free_private(iface);
2309 /* Release the buffers (with sanity checks)*/
2310 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2311 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2312 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2313 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2315 This->stencilBufferTarget = NULL;
2317 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2318 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2319 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2321 TRACE("Setting rendertarget to NULL\n");
2322 This->render_targets[0] = NULL;
2324 if (This->auto_depth_stencil_buffer) {
2325 if (IWineD3DSurface_Release(This->auto_depth_stencil_buffer) > 0)
2327 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2329 This->auto_depth_stencil_buffer = NULL;
2332 for(i=0; i < This->NumberOfSwapChains; i++) {
2333 TRACE("Releasing the implicit swapchain %d\n", i);
2334 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2335 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2339 HeapFree(GetProcessHeap(), 0, This->swapchains);
2340 This->swapchains = NULL;
2341 This->NumberOfSwapChains = 0;
2343 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2344 HeapFree(GetProcessHeap(), 0, This->palettes);
2345 This->palettes = NULL;
2346 This->NumberOfPalettes = 0;
2348 HeapFree(GetProcessHeap(), 0, This->render_targets);
2349 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2350 This->render_targets = NULL;
2351 This->draw_buffers = NULL;
2353 This->d3d_initialized = FALSE;
2357 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2358 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2361 for(i=0; i < This->NumberOfSwapChains; i++) {
2362 TRACE("Releasing the implicit swapchain %d\n", i);
2363 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2364 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2368 HeapFree(GetProcessHeap(), 0, This->swapchains);
2369 This->swapchains = NULL;
2370 This->NumberOfSwapChains = 0;
2374 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2375 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2376 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2378 * There is no way to deactivate thread safety once it is enabled.
2380 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2381 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2383 /*For now just store the flag(needed in case of ddraw) */
2384 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2389 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2390 const WINED3DDISPLAYMODE* pMode) {
2392 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2394 const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(pMode->Format, &GLINFO_LOCATION);
2397 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2399 /* Resize the screen even without a window:
2400 * The app could have unset it with SetCooperativeLevel, but not called
2401 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2402 * but we don't have any hwnd
2405 memset(&devmode, 0, sizeof(devmode));
2406 devmode.dmSize = sizeof(devmode);
2407 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2408 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2409 devmode.dmPelsWidth = pMode->Width;
2410 devmode.dmPelsHeight = pMode->Height;
2412 devmode.dmDisplayFrequency = pMode->RefreshRate;
2413 if (pMode->RefreshRate != 0) {
2414 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2417 /* Only change the mode if necessary */
2418 if( (This->ddraw_width == pMode->Width) &&
2419 (This->ddraw_height == pMode->Height) &&
2420 (This->ddraw_format == pMode->Format) &&
2421 (pMode->RefreshRate == 0) ) {
2425 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2426 if (ret != DISP_CHANGE_SUCCESSFUL) {
2427 if(devmode.dmDisplayFrequency != 0) {
2428 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2429 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2430 devmode.dmDisplayFrequency = 0;
2431 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2433 if(ret != DISP_CHANGE_SUCCESSFUL) {
2434 return WINED3DERR_NOTAVAILABLE;
2438 /* Store the new values */
2439 This->ddraw_width = pMode->Width;
2440 This->ddraw_height = pMode->Height;
2441 This->ddraw_format = pMode->Format;
2443 /* And finally clip mouse to our screen */
2444 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2445 ClipCursor(&clip_rc);
2450 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2451 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2452 *ppD3D= This->wineD3D;
2453 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2454 IWineD3D_AddRef(*ppD3D);
2458 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2459 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2461 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2462 (This->adapter->TextureRam/(1024*1024)),
2463 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2464 /* return simulated texture memory left */
2465 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2469 * Get / Set Stream Source
2471 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2472 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2474 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2475 IWineD3DBuffer *oldSrc;
2477 if (StreamNumber >= MAX_STREAMS) {
2478 WARN("Stream out of range %d\n", StreamNumber);
2479 return WINED3DERR_INVALIDCALL;
2480 } else if(OffsetInBytes & 0x3) {
2481 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2482 return WINED3DERR_INVALIDCALL;
2485 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2486 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2488 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2490 if(oldSrc == pStreamData &&
2491 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2492 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2493 TRACE("Application is setting the old values over, nothing to do\n");
2497 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2499 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2500 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2503 /* Handle recording of state blocks */
2504 if (This->isRecordingState) {
2505 TRACE("Recording... not performing anything\n");
2506 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2507 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2511 if (pStreamData != NULL) {
2512 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2513 IWineD3DBuffer_AddRef(pStreamData);
2515 if (oldSrc != NULL) {
2516 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2517 IWineD3DBuffer_Release(oldSrc);
2520 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2525 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2526 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2528 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2530 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2531 This->stateBlock->streamSource[StreamNumber],
2532 This->stateBlock->streamOffset[StreamNumber],
2533 This->stateBlock->streamStride[StreamNumber]);
2535 if (StreamNumber >= MAX_STREAMS) {
2536 WARN("Stream out of range %d\n", StreamNumber);
2537 return WINED3DERR_INVALIDCALL;
2539 *pStream = This->stateBlock->streamSource[StreamNumber];
2540 *pStride = This->stateBlock->streamStride[StreamNumber];
2542 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2545 if (*pStream != NULL) {
2546 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2551 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2552 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2553 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2554 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2556 /* Verify input at least in d3d9 this is invalid*/
2557 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2558 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2559 return WINED3DERR_INVALIDCALL;
2561 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2562 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2563 return WINED3DERR_INVALIDCALL;
2566 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2567 return WINED3DERR_INVALIDCALL;
2570 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2571 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2573 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2574 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2576 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2577 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2578 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2584 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2585 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2587 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2588 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2590 TRACE("(%p) : returning %d\n", This, *Divider);
2596 * Get / Set & Multiply Transform
2598 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2599 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2601 /* Most of this routine, comments included copied from ddraw tree initially: */
2602 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2604 /* Handle recording of state blocks */
2605 if (This->isRecordingState) {
2606 TRACE("Recording... not performing anything\n");
2607 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2608 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2613 * If the new matrix is the same as the current one,
2614 * we cut off any further processing. this seems to be a reasonable
2615 * optimization because as was noticed, some apps (warcraft3 for example)
2616 * tend towards setting the same matrix repeatedly for some reason.
2618 * From here on we assume that the new matrix is different, wherever it matters.
2620 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2621 TRACE("The app is setting the same matrix over again\n");
2624 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2628 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2629 where ViewMat = Camera space, WorldMat = world space.
2631 In OpenGL, camera and world space is combined into GL_MODELVIEW
2632 matrix. The Projection matrix stay projection matrix.
2635 /* Capture the times we can just ignore the change for now */
2636 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2637 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2638 /* Handled by the state manager */
2641 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2645 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2646 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2647 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2648 *pMatrix = This->stateBlock->transforms[State];
2652 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2653 const WINED3DMATRIX *mat = NULL;
2656 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2657 * below means it will be recorded in a state block change, but it
2658 * works regardless where it is recorded.
2659 * If this is found to be wrong, change to StateBlock.
2661 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2662 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2664 if (State <= HIGHEST_TRANSFORMSTATE)
2666 mat = &This->updateStateBlock->transforms[State];
2668 FIXME("Unhandled transform state!!\n");
2671 multiply_matrix(&temp, mat, pMatrix);
2673 /* Apply change via set transform - will reapply to eg. lights this way */
2674 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2680 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2681 you can reference any indexes you want as long as that number max are enabled at any
2682 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2683 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2684 but when recording, just build a chain pretty much of commands to be replayed. */
2686 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2688 PLIGHTINFOEL *object = NULL;
2689 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2692 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2693 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2695 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2699 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2700 return WINED3DERR_INVALIDCALL;
2703 switch(pLight->Type) {
2704 case WINED3DLIGHT_POINT:
2705 case WINED3DLIGHT_SPOT:
2706 case WINED3DLIGHT_PARALLELPOINT:
2707 case WINED3DLIGHT_GLSPOT:
2708 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2711 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2713 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2714 return WINED3DERR_INVALIDCALL;
2718 case WINED3DLIGHT_DIRECTIONAL:
2719 /* Ignores attenuation */
2723 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2724 return WINED3DERR_INVALIDCALL;
2727 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2728 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2729 if(object->OriginalIndex == Index) break;
2734 TRACE("Adding new light\n");
2735 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2737 ERR("Out of memory error when allocating a light\n");
2738 return E_OUTOFMEMORY;
2740 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2741 object->glIndex = -1;
2742 object->OriginalIndex = Index;
2743 object->changed = TRUE;
2746 /* Initialize the object */
2747 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,
2748 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2749 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2750 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2751 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2752 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2753 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2755 /* Save away the information */
2756 object->OriginalParms = *pLight;
2758 switch (pLight->Type) {
2759 case WINED3DLIGHT_POINT:
2761 object->lightPosn[0] = pLight->Position.x;
2762 object->lightPosn[1] = pLight->Position.y;
2763 object->lightPosn[2] = pLight->Position.z;
2764 object->lightPosn[3] = 1.0f;
2765 object->cutoff = 180.0f;
2769 case WINED3DLIGHT_DIRECTIONAL:
2771 object->lightPosn[0] = -pLight->Direction.x;
2772 object->lightPosn[1] = -pLight->Direction.y;
2773 object->lightPosn[2] = -pLight->Direction.z;
2774 object->lightPosn[3] = 0.0f;
2775 object->exponent = 0.0f;
2776 object->cutoff = 180.0f;
2779 case WINED3DLIGHT_SPOT:
2781 object->lightPosn[0] = pLight->Position.x;
2782 object->lightPosn[1] = pLight->Position.y;
2783 object->lightPosn[2] = pLight->Position.z;
2784 object->lightPosn[3] = 1.0f;
2787 object->lightDirn[0] = pLight->Direction.x;
2788 object->lightDirn[1] = pLight->Direction.y;
2789 object->lightDirn[2] = pLight->Direction.z;
2790 object->lightDirn[3] = 1.0f;
2793 * opengl-ish and d3d-ish spot lights use too different models for the
2794 * light "intensity" as a function of the angle towards the main light direction,
2795 * so we only can approximate very roughly.
2796 * however spot lights are rather rarely used in games (if ever used at all).
2797 * furthermore if still used, probably nobody pays attention to such details.
2799 if (pLight->Falloff == 0) {
2800 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2801 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2802 * will always be 1.0 for both of them, and we don't have to care for the
2803 * rest of the rather complex calculation
2805 object->exponent = 0.0f;
2807 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2808 if (rho < 0.0001f) rho = 0.0001f;
2809 object->exponent = -0.3f/logf(cosf(rho/2));
2811 if (object->exponent > 128.0f)
2813 object->exponent = 128.0f;
2815 object->cutoff = pLight->Phi*90/M_PI;
2821 FIXME("Unrecognized light type %d\n", pLight->Type);
2824 /* Update the live definitions if the light is currently assigned a glIndex */
2825 if (object->glIndex != -1 && !This->isRecordingState) {
2826 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2831 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2832 PLIGHTINFOEL *lightInfo = NULL;
2833 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2834 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2836 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2838 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2839 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2840 if(lightInfo->OriginalIndex == Index) break;
2844 if (lightInfo == NULL) {
2845 TRACE("Light information requested but light not defined\n");
2846 return WINED3DERR_INVALIDCALL;
2849 *pLight = lightInfo->OriginalParms;
2854 * Get / Set Light Enable
2855 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2857 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2858 PLIGHTINFOEL *lightInfo = NULL;
2859 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2860 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2862 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2864 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2865 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2866 if(lightInfo->OriginalIndex == Index) break;
2869 TRACE("Found light: %p\n", lightInfo);
2871 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2872 if (lightInfo == NULL) {
2874 TRACE("Light enabled requested but light not defined, so defining one!\n");
2875 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2877 /* Search for it again! Should be fairly quick as near head of list */
2878 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2879 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2880 if(lightInfo->OriginalIndex == Index) break;
2883 if (lightInfo == NULL) {
2884 FIXME("Adding default lights has failed dismally\n");
2885 return WINED3DERR_INVALIDCALL;
2889 lightInfo->enabledChanged = TRUE;
2891 if(lightInfo->glIndex != -1) {
2892 if(!This->isRecordingState) {
2893 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2896 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2897 lightInfo->glIndex = -1;
2899 TRACE("Light already disabled, nothing to do\n");
2901 lightInfo->enabled = FALSE;
2903 lightInfo->enabled = TRUE;
2904 if (lightInfo->glIndex != -1) {
2906 TRACE("Nothing to do as light was enabled\n");
2909 /* Find a free gl light */
2910 for(i = 0; i < This->maxConcurrentLights; i++) {
2911 if(This->updateStateBlock->activeLights[i] == NULL) {
2912 This->updateStateBlock->activeLights[i] = lightInfo;
2913 lightInfo->glIndex = i;
2917 if(lightInfo->glIndex == -1) {
2918 /* Our tests show that Windows returns D3D_OK in this situation, even with
2919 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2920 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2921 * as well for those lights.
2923 * TODO: Test how this affects rendering
2925 WARN("Too many concurrently active lights\n");
2929 /* i == lightInfo->glIndex */
2930 if(!This->isRecordingState) {
2931 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2939 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2941 PLIGHTINFOEL *lightInfo = NULL;
2942 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2944 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2945 TRACE("(%p) : for idx(%d)\n", This, Index);
2947 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2948 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2949 if(lightInfo->OriginalIndex == Index) break;
2953 if (lightInfo == NULL) {
2954 TRACE("Light enabled state requested but light not defined\n");
2955 return WINED3DERR_INVALIDCALL;
2957 /* true is 128 according to SetLightEnable */
2958 *pEnable = lightInfo->enabled ? 128 : 0;
2963 * Get / Set Clip Planes
2965 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2966 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2967 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2969 /* Validate Index */
2970 if (Index >= GL_LIMITS(clipplanes)) {
2971 TRACE("Application has requested clipplane this device doesn't support\n");
2972 return WINED3DERR_INVALIDCALL;
2975 This->updateStateBlock->changed.clipplane |= 1 << Index;
2977 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2978 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2979 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2980 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2981 TRACE("Application is setting old values over, nothing to do\n");
2985 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2986 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2987 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2988 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2990 /* Handle recording of state blocks */
2991 if (This->isRecordingState) {
2992 TRACE("Recording... not performing anything\n");
2996 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3001 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3002 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3003 TRACE("(%p) : for idx %d\n", This, Index);
3005 /* Validate Index */
3006 if (Index >= GL_LIMITS(clipplanes)) {
3007 TRACE("Application has requested clipplane this device doesn't support\n");
3008 return WINED3DERR_INVALIDCALL;
3011 pPlane[0] = This->stateBlock->clipplane[Index][0];
3012 pPlane[1] = This->stateBlock->clipplane[Index][1];
3013 pPlane[2] = This->stateBlock->clipplane[Index][2];
3014 pPlane[3] = This->stateBlock->clipplane[Index][3];
3019 * Get / Set Clip Plane Status
3020 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3022 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3023 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3024 FIXME("(%p) : stub\n", This);
3025 if (NULL == pClipStatus) {
3026 return WINED3DERR_INVALIDCALL;
3028 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3029 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3033 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3034 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3035 FIXME("(%p) : stub\n", This);
3036 if (NULL == pClipStatus) {
3037 return WINED3DERR_INVALIDCALL;
3039 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3040 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3045 * Get / Set Material
3047 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3048 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3050 This->updateStateBlock->changed.material = TRUE;
3051 This->updateStateBlock->material = *pMaterial;
3053 /* Handle recording of state blocks */
3054 if (This->isRecordingState) {
3055 TRACE("Recording... not performing anything\n");
3059 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3063 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3064 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3065 *pMaterial = This->updateStateBlock->material;
3066 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3067 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3068 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3069 pMaterial->Ambient.b, pMaterial->Ambient.a);
3070 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3071 pMaterial->Specular.b, pMaterial->Specular.a);
3072 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3073 pMaterial->Emissive.b, pMaterial->Emissive.a);
3074 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3082 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DBuffer* pIndexData, WINED3DFORMAT fmt) {
3083 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3084 IWineD3DBuffer *oldIdxs;
3086 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3087 oldIdxs = This->updateStateBlock->pIndexData;
3089 This->updateStateBlock->changed.indices = TRUE;
3090 This->updateStateBlock->pIndexData = pIndexData;
3091 This->updateStateBlock->IndexFmt = fmt;
3093 /* Handle recording of state blocks */
3094 if (This->isRecordingState) {
3095 TRACE("Recording... not performing anything\n");
3096 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
3097 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
3101 if(oldIdxs != pIndexData) {
3102 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3104 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
3105 IWineD3DBuffer_AddRef(pIndexData);
3108 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
3109 IWineD3DBuffer_Release(oldIdxs);
3116 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DBuffer** ppIndexData) {
3117 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3119 *ppIndexData = This->stateBlock->pIndexData;
3121 /* up ref count on ppindexdata */
3123 IWineD3DBuffer_AddRef(*ppIndexData);
3124 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3126 TRACE("(%p) No index data set\n", This);
3128 TRACE("Returning %p\n", *ppIndexData);
3133 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3134 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3135 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3136 TRACE("(%p)->(%d)\n", This, BaseIndex);
3138 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3139 TRACE("Application is setting the old value over, nothing to do\n");
3143 This->updateStateBlock->baseVertexIndex = BaseIndex;
3145 if (This->isRecordingState) {
3146 TRACE("Recording... not performing anything\n");
3149 /* The base vertex index affects the stream sources */
3150 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3154 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3155 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3156 TRACE("(%p) : base_index %p\n", This, base_index);
3158 *base_index = This->stateBlock->baseVertexIndex;
3160 TRACE("Returning %u\n", *base_index);
3166 * Get / Set Viewports
3168 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3169 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3171 TRACE("(%p)\n", This);
3172 This->updateStateBlock->changed.viewport = TRUE;
3173 This->updateStateBlock->viewport = *pViewport;
3175 /* Handle recording of state blocks */
3176 if (This->isRecordingState) {
3177 TRACE("Recording... not performing anything\n");
3181 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3182 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3184 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3189 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3190 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3191 TRACE("(%p)\n", This);
3192 *pViewport = This->stateBlock->viewport;
3197 * Get / Set Render States
3198 * TODO: Verify against dx9 definitions
3200 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3203 DWORD oldValue = This->stateBlock->renderState[State];
3205 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3207 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3208 This->updateStateBlock->renderState[State] = Value;
3210 /* Handle recording of state blocks */
3211 if (This->isRecordingState) {
3212 TRACE("Recording... not performing anything\n");
3216 /* Compared here and not before the assignment to allow proper stateblock recording */
3217 if(Value == oldValue) {
3218 TRACE("Application is setting the old value over, nothing to do\n");
3220 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3226 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3228 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3229 *pValue = This->stateBlock->renderState[State];
3234 * Get / Set Sampler States
3235 * TODO: Verify against dx9 definitions
3238 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3239 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3242 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3243 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3245 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3246 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3249 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3250 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3251 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3254 * SetSampler is designed to allow for more than the standard up to 8 textures
3255 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3256 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3258 * http://developer.nvidia.com/object/General_FAQ.html#t6
3260 * There are two new settings for GForce
3262 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3263 * and the texture one:
3264 * GL_MAX_TEXTURE_COORDS_ARB.
3265 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3268 oldValue = This->stateBlock->samplerState[Sampler][Type];
3269 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3270 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3272 /* Handle recording of state blocks */
3273 if (This->isRecordingState) {
3274 TRACE("Recording... not performing anything\n");
3278 if(oldValue == Value) {
3279 TRACE("Application is setting the old value over, nothing to do\n");
3283 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3288 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3289 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3291 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3292 This, Sampler, debug_d3dsamplerstate(Type), Type);
3294 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3295 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3298 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3299 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3300 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3302 *Value = This->stateBlock->samplerState[Sampler][Type];
3303 TRACE("(%p) : Returning %#x\n", This, *Value);
3308 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3309 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3311 This->updateStateBlock->changed.scissorRect = TRUE;
3312 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3313 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3316 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3318 if(This->isRecordingState) {
3319 TRACE("Recording... not performing anything\n");
3323 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3328 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3329 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3331 *pRect = This->updateStateBlock->scissorRect;
3332 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3336 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3337 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3338 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3340 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3342 This->updateStateBlock->vertexDecl = pDecl;
3343 This->updateStateBlock->changed.vertexDecl = TRUE;
3345 if (This->isRecordingState) {
3346 TRACE("Recording... not performing anything\n");
3348 } else if(pDecl == oldDecl) {
3349 /* Checked after the assignment to allow proper stateblock recording */
3350 TRACE("Application is setting the old declaration over, nothing to do\n");
3354 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3358 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3359 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3361 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3363 *ppDecl = This->stateBlock->vertexDecl;
3364 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3368 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3369 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3370 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3372 This->updateStateBlock->vertexShader = pShader;
3373 This->updateStateBlock->changed.vertexShader = TRUE;
3375 if (This->isRecordingState) {
3376 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3377 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3378 TRACE("Recording... not performing anything\n");
3380 } else if(oldShader == pShader) {
3381 /* Checked here to allow proper stateblock recording */
3382 TRACE("App is setting the old shader over, nothing to do\n");
3386 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3387 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3388 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3390 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3395 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3396 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3398 if (NULL == ppShader) {
3399 return WINED3DERR_INVALIDCALL;
3401 *ppShader = This->stateBlock->vertexShader;
3402 if( NULL != *ppShader)
3403 IWineD3DVertexShader_AddRef(*ppShader);
3405 TRACE("(%p) : returning %p\n", This, *ppShader);
3409 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3410 IWineD3DDevice *iface,
3412 CONST BOOL *srcData,
3415 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3416 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3418 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3419 iface, srcData, start, count);
3421 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3423 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3424 for (i = 0; i < cnt; i++)
3425 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3427 for (i = start; i < cnt + start; ++i) {
3428 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3431 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3436 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3437 IWineD3DDevice *iface,
3442 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3443 int cnt = min(count, MAX_CONST_B - start);
3445 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3446 iface, dstData, start, count);
3448 if (dstData == NULL || cnt < 0)
3449 return WINED3DERR_INVALIDCALL;
3451 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3455 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3456 IWineD3DDevice *iface,
3461 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3462 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3464 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3465 iface, srcData, start, count);
3467 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3469 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3470 for (i = 0; i < cnt; i++)
3471 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3472 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3474 for (i = start; i < cnt + start; ++i) {
3475 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3478 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3483 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3484 IWineD3DDevice *iface,
3489 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3490 int cnt = min(count, MAX_CONST_I - start);
3492 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3493 iface, dstData, start, count);
3495 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3496 return WINED3DERR_INVALIDCALL;
3498 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3502 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3503 IWineD3DDevice *iface,
3505 CONST float *srcData,
3508 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3511 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3512 iface, srcData, start, count);
3514 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3515 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3516 return WINED3DERR_INVALIDCALL;
3518 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3520 for (i = 0; i < count; i++)
3521 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3522 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3525 if (!This->isRecordingState)
3527 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3528 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3531 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3532 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3537 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3538 IWineD3DDevice *iface,
3543 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3544 int cnt = min(count, This->d3d_vshader_constantF - start);
3546 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3547 iface, dstData, start, count);
3549 if (dstData == NULL || cnt < 0)
3550 return WINED3DERR_INVALIDCALL;
3552 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3556 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3558 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3560 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3564 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3566 DWORD i = This->rev_tex_unit_map[unit];
3567 DWORD j = This->texUnitMap[stage];
3569 This->texUnitMap[stage] = unit;
3570 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3572 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3575 This->rev_tex_unit_map[unit] = stage;
3576 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3578 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3582 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3585 This->fixed_function_usage_map = 0;
3586 for (i = 0; i < MAX_TEXTURES; ++i) {
3587 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3588 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3589 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3590 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3591 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3592 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3593 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3594 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3596 if (color_op == WINED3DTOP_DISABLE) {
3597 /* Not used, and disable higher stages */
3601 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3602 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3603 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3604 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3605 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3606 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3607 This->fixed_function_usage_map |= (1 << i);
3610 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3611 This->fixed_function_usage_map |= (1 << (i + 1));
3616 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3617 unsigned int i, tex;
3620 device_update_fixed_function_usage_map(This);
3621 ffu_map = This->fixed_function_usage_map;
3623 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3624 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3625 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3627 if (!(ffu_map & 1)) continue;
3629 if (This->texUnitMap[i] != i) {
3630 device_map_stage(This, i, i);
3631 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3632 markTextureStagesDirty(This, i);
3638 /* Now work out the mapping */
3640 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3642 if (!(ffu_map & 1)) continue;
3644 if (This->texUnitMap[i] != tex) {
3645 device_map_stage(This, i, tex);
3646 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3647 markTextureStagesDirty(This, i);
3654 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3655 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3656 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3659 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3660 if (sampler_type[i] && This->texUnitMap[i] != i)
3662 device_map_stage(This, i, i);
3663 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3664 if (i < MAX_TEXTURES) {
3665 markTextureStagesDirty(This, i);
3671 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3672 const DWORD *vshader_sampler_tokens, DWORD unit)
3674 DWORD current_mapping = This->rev_tex_unit_map[unit];
3676 /* Not currently used */
3677 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3679 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3680 /* Used by a fragment sampler */
3682 if (!pshader_sampler_tokens) {
3683 /* No pixel shader, check fixed function */
3684 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3687 /* Pixel shader, check the shader's sampler map */
3688 return !pshader_sampler_tokens[current_mapping];
3691 /* Used by a vertex sampler */
3692 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3695 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3696 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3697 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3698 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3699 int start = min(MAX_COMBINED_SAMPLERS, GL_LIMITS(combined_samplers)) - 1;
3703 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3705 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3706 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3707 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3710 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3711 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3712 if (vshader_sampler_type[i])
3714 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3716 /* Already mapped somewhere */
3720 while (start >= 0) {
3721 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3723 device_map_stage(This, vsampler_idx, start);
3724 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3736 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3737 BOOL vs = use_vs(This->stateBlock);
3738 BOOL ps = use_ps(This->stateBlock);
3741 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3742 * that would be really messy and require shader recompilation
3743 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3744 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3747 device_map_psamplers(This);
3749 device_map_fixed_function_samplers(This);
3753 device_map_vsamplers(This, ps);
3757 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3758 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3759 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3760 This->updateStateBlock->pixelShader = pShader;
3761 This->updateStateBlock->changed.pixelShader = TRUE;
3763 /* Handle recording of state blocks */
3764 if (This->isRecordingState) {
3765 TRACE("Recording... not performing anything\n");
3768 if (This->isRecordingState) {
3769 TRACE("Recording... not performing anything\n");
3770 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3771 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3775 if(pShader == oldShader) {
3776 TRACE("App is setting the old pixel shader over, nothing to do\n");
3780 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3781 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3783 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3784 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3789 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3790 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3792 if (NULL == ppShader) {
3793 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3794 return WINED3DERR_INVALIDCALL;
3797 *ppShader = This->stateBlock->pixelShader;
3798 if (NULL != *ppShader) {
3799 IWineD3DPixelShader_AddRef(*ppShader);
3801 TRACE("(%p) : returning %p\n", This, *ppShader);
3805 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3806 IWineD3DDevice *iface,
3808 CONST BOOL *srcData,
3811 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3812 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3814 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3815 iface, srcData, start, count);
3817 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3819 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3820 for (i = 0; i < cnt; i++)
3821 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3823 for (i = start; i < cnt + start; ++i) {
3824 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3827 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3832 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3833 IWineD3DDevice *iface,
3838 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3839 int cnt = min(count, MAX_CONST_B - start);
3841 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3842 iface, dstData, start, count);
3844 if (dstData == NULL || cnt < 0)
3845 return WINED3DERR_INVALIDCALL;
3847 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3851 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3852 IWineD3DDevice *iface,
3857 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3858 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3860 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3861 iface, srcData, start, count);
3863 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3865 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3866 for (i = 0; i < cnt; i++)
3867 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3868 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3870 for (i = start; i < cnt + start; ++i) {
3871 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3874 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3879 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3880 IWineD3DDevice *iface,
3885 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3886 int cnt = min(count, MAX_CONST_I - start);
3888 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3889 iface, dstData, start, count);
3891 if (dstData == NULL || cnt < 0)
3892 return WINED3DERR_INVALIDCALL;
3894 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3898 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3899 IWineD3DDevice *iface,
3901 CONST float *srcData,
3904 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3907 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3908 iface, srcData, start, count);
3910 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3911 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3912 return WINED3DERR_INVALIDCALL;
3914 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3916 for (i = 0; i < count; i++)
3917 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3918 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3921 if (!This->isRecordingState)
3923 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3924 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3927 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3928 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3933 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3934 IWineD3DDevice *iface,
3939 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3940 int cnt = min(count, This->d3d_pshader_constantF - start);
3942 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3943 iface, dstData, start, count);
3945 if (dstData == NULL || cnt < 0)
3946 return WINED3DERR_INVALIDCALL;
3948 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3952 /* Context activation is done by the caller. */
3953 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3954 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3955 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3958 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3961 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3965 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3967 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3970 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3972 ERR("Source has no position mask\n");
3973 return WINED3DERR_INVALIDCALL;
3976 /* We might access VBOs from this code, so hold the lock */
3979 if (dest->resource.allocatedMemory == NULL) {
3980 buffer_get_sysmem(dest);
3983 /* Get a pointer into the destination vbo(create one if none exists) and
3984 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3986 if (!dest->buffer_object && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT))
3988 dest->flags |= WINED3D_BUFFER_CREATEBO;
3989 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3992 if (dest->buffer_object)
3994 unsigned char extrabytes = 0;
3995 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3996 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3997 * this may write 4 extra bytes beyond the area that should be written
3999 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4000 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4001 if(!dest_conv_addr) {
4002 ERR("Out of memory\n");
4003 /* Continue without storing converted vertices */
4005 dest_conv = dest_conv_addr;
4009 * a) WINED3DRS_CLIPPING is enabled
4010 * b) WINED3DVOP_CLIP is passed
4012 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4013 static BOOL warned = FALSE;
4015 * The clipping code is not quite correct. Some things need
4016 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4017 * so disable clipping for now.
4018 * (The graphics in Half-Life are broken, and my processvertices
4019 * test crashes with IDirect3DDevice3)
4025 FIXME("Clipping is broken and disabled for now\n");
4027 } else doClip = FALSE;
4028 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4030 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4033 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4034 WINED3DTS_PROJECTION,
4036 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4037 WINED3DTS_WORLDMATRIX(0),
4040 TRACE("View mat:\n");
4041 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);
4042 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);
4043 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);
4044 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);
4046 TRACE("Proj mat:\n");
4047 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);
4048 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);
4049 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);
4050 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);
4052 TRACE("World mat:\n");
4053 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);
4054 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);
4055 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);
4056 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);
4058 /* Get the viewport */
4059 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4060 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4061 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4063 multiply_matrix(&mat,&view_mat,&world_mat);
4064 multiply_matrix(&mat,&proj_mat,&mat);
4066 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4068 for (i = 0; i < dwCount; i+= 1) {
4069 unsigned int tex_index;
4071 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4072 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4073 /* The position first */
4074 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
4075 const float *p = (const float *)(element->data + i * element->stride);
4077 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4079 /* Multiplication with world, view and projection matrix */
4080 x = (p[0] * mat.u.s._11) + (p[1] * mat.u.s._21) + (p[2] * mat.u.s._31) + (1.0f * mat.u.s._41);
4081 y = (p[0] * mat.u.s._12) + (p[1] * mat.u.s._22) + (p[2] * mat.u.s._32) + (1.0f * mat.u.s._42);
4082 z = (p[0] * mat.u.s._13) + (p[1] * mat.u.s._23) + (p[2] * mat.u.s._33) + (1.0f * mat.u.s._43);
4083 rhw = (p[0] * mat.u.s._14) + (p[1] * mat.u.s._24) + (p[2] * mat.u.s._34) + (1.0f * mat.u.s._44);
4085 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4087 /* WARNING: The following things are taken from d3d7 and were not yet checked
4088 * against d3d8 or d3d9!
4091 /* Clipping conditions: From msdn
4093 * A vertex is clipped if it does not match the following requirements
4097 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4099 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4100 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4105 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4106 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4109 /* "Normal" viewport transformation (not clipped)
4110 * 1) The values are divided by rhw
4111 * 2) The y axis is negative, so multiply it with -1
4112 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4113 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4114 * 4) Multiply x with Width/2 and add Width/2
4115 * 5) The same for the height
4116 * 6) Add the viewpoint X and Y to the 2D coordinates and
4117 * The minimum Z value to z
4118 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4120 * Well, basically it's simply a linear transformation into viewport
4132 z *= vp.MaxZ - vp.MinZ;
4134 x += vp.Width / 2 + vp.X;
4135 y += vp.Height / 2 + vp.Y;
4140 /* That vertex got clipped
4141 * Contrary to OpenGL it is not dropped completely, it just
4142 * undergoes a different calculation.
4144 TRACE("Vertex got clipped\n");
4151 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4152 * outside of the main vertex buffer memory. That needs some more
4157 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4160 ( (float *) dest_ptr)[0] = x;
4161 ( (float *) dest_ptr)[1] = y;
4162 ( (float *) dest_ptr)[2] = z;
4163 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4165 dest_ptr += 3 * sizeof(float);
4167 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4168 dest_ptr += sizeof(float);
4173 ( (float *) dest_conv)[0] = x * w;
4174 ( (float *) dest_conv)[1] = y * w;
4175 ( (float *) dest_conv)[2] = z * w;
4176 ( (float *) dest_conv)[3] = w;
4178 dest_conv += 3 * sizeof(float);
4180 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4181 dest_conv += sizeof(float);
4185 if (DestFVF & WINED3DFVF_PSIZE) {
4186 dest_ptr += sizeof(DWORD);
4187 if(dest_conv) dest_conv += sizeof(DWORD);
4189 if (DestFVF & WINED3DFVF_NORMAL) {
4190 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4191 const float *normal = (const float *)(element->data + i * element->stride);
4192 /* AFAIK this should go into the lighting information */
4193 FIXME("Didn't expect the destination to have a normal\n");
4194 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4196 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4200 if (DestFVF & WINED3DFVF_DIFFUSE) {
4201 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4202 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4203 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4205 static BOOL warned = FALSE;
4208 ERR("No diffuse color in source, but destination has one\n");
4212 *( (DWORD *) dest_ptr) = 0xffffffff;
4213 dest_ptr += sizeof(DWORD);
4216 *( (DWORD *) dest_conv) = 0xffffffff;
4217 dest_conv += sizeof(DWORD);
4221 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4223 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4224 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4225 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4226 dest_conv += sizeof(DWORD);
4231 if (DestFVF & WINED3DFVF_SPECULAR)
4233 /* What's the color value in the feedback buffer? */
4234 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4235 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4236 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4238 static BOOL warned = FALSE;
4241 ERR("No specular color in source, but destination has one\n");
4245 *( (DWORD *) dest_ptr) = 0xFF000000;
4246 dest_ptr += sizeof(DWORD);
4249 *( (DWORD *) dest_conv) = 0xFF000000;
4250 dest_conv += sizeof(DWORD);
4254 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4256 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4257 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4258 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4259 dest_conv += sizeof(DWORD);
4264 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4265 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4266 const float *tex_coord = (const float *)(element->data + i * element->stride);
4267 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4269 ERR("No source texture, but destination requests one\n");
4270 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4271 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4274 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4276 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4283 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4284 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4285 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4286 dwCount * get_flexible_vertex_size(DestFVF),
4288 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4289 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4296 #undef copy_and_next
4298 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4299 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4302 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4303 struct wined3d_stream_info stream_info;
4304 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4305 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4308 ERR("Output vertex declaration not implemented yet\n");
4311 /* Need any context to write to the vbo. */
4312 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
4314 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4315 * control the streamIsUP flag, thus restore it afterwards.
4317 This->stateBlock->streamIsUP = FALSE;
4318 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4319 This->stateBlock->streamIsUP = streamWasUP;
4321 if(vbo || SrcStartIndex) {
4323 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4324 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4326 * Also get the start index in, but only loop over all elements if there's something to add at all.
4328 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4330 struct wined3d_stream_info_element *e;
4332 if (!(stream_info.use_map & (1 << i))) continue;
4334 e = &stream_info.elements[i];
4335 if (e->buffer_object)
4337 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
4338 e->buffer_object = 0;
4339 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
4341 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4342 vb->buffer_object = 0;
4345 if (e->data) e->data += e->stride * SrcStartIndex;
4349 return process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4350 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4354 * Get / Set Texture Stage States
4355 * TODO: Verify against dx9 definitions
4357 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4358 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4359 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4361 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4363 if (Stage >= MAX_TEXTURES) {
4364 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4368 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4369 This->updateStateBlock->textureState[Stage][Type] = Value;
4371 if (This->isRecordingState) {
4372 TRACE("Recording... not performing anything\n");
4376 /* Checked after the assignments to allow proper stateblock recording */
4377 if(oldValue == Value) {
4378 TRACE("App is setting the old value over, nothing to do\n");
4382 if(Stage > This->stateBlock->lowest_disabled_stage &&
4383 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4384 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4385 * Changes in other states are important on disabled stages too
4390 if(Type == WINED3DTSS_COLOROP) {
4393 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4394 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4395 * they have to be disabled
4397 * The current stage is dirtified below.
4399 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4400 TRACE("Additionally dirtifying stage %u\n", i);
4401 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4403 This->stateBlock->lowest_disabled_stage = Stage;
4404 TRACE("New lowest disabled: %u\n", Stage);
4405 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4406 /* Previously disabled stage enabled. Stages above it may need enabling
4407 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4408 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4410 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4413 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4414 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4417 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4418 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4420 This->stateBlock->lowest_disabled_stage = i;
4421 TRACE("New lowest disabled: %u\n", i);
4425 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4430 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4431 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4432 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4433 *pValue = This->updateStateBlock->textureState[Stage][Type];
4440 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4441 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4442 IWineD3DBaseTexture *oldTexture;
4444 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4446 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4447 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4450 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4451 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4452 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4455 oldTexture = This->updateStateBlock->textures[Stage];
4457 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4458 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
4460 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4461 return WINED3DERR_INVALIDCALL;
4464 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4465 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4467 This->updateStateBlock->changed.textures |= 1 << Stage;
4468 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4469 This->updateStateBlock->textures[Stage] = pTexture;
4471 /* Handle recording of state blocks */
4472 if (This->isRecordingState) {
4473 TRACE("Recording... not performing anything\n");
4477 if(oldTexture == pTexture) {
4478 TRACE("App is setting the same texture again, nothing to do\n");
4482 /** NOTE: MSDN says that setTexture increases the reference count,
4483 * and that the application must set the texture back to null (or have a leaky application),
4484 * This means we should pass the refcount up to the parent
4485 *******************************/
4486 if (NULL != This->updateStateBlock->textures[Stage]) {
4487 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4488 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4489 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4491 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4493 if (!oldTexture || dimensions != IWineD3DBaseTexture_GetTextureDimensions(oldTexture))
4495 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4498 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4499 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4500 * so the COLOROP and ALPHAOP have to be dirtified.
4502 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4503 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4505 if(bindCount == 1) {
4506 new->baseTexture.sampler = Stage;
4508 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4512 if (NULL != oldTexture) {
4513 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4514 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4516 IWineD3DBaseTexture_Release(oldTexture);
4517 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4518 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4519 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4522 if(bindCount && old->baseTexture.sampler == Stage) {
4524 /* Have to do a search for the other sampler(s) where the texture is bound to
4525 * Shouldn't happen as long as apps bind a texture only to one stage
4527 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4528 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4529 if(This->updateStateBlock->textures[i] == oldTexture) {
4530 old->baseTexture.sampler = i;
4537 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4542 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4543 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4545 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4547 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4548 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4551 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4552 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4553 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4556 *ppTexture=This->stateBlock->textures[Stage];
4558 IWineD3DBaseTexture_AddRef(*ppTexture);
4560 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4568 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4569 IWineD3DSurface **ppBackBuffer) {
4570 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4571 IWineD3DSwapChain *swapChain;
4574 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4576 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4577 if (hr == WINED3D_OK) {
4578 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4579 IWineD3DSwapChain_Release(swapChain);
4581 *ppBackBuffer = NULL;
4586 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4587 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4588 WARN("(%p) : stub, calling idirect3d for now\n", This);
4589 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4592 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4593 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4594 IWineD3DSwapChain *swapChain;
4597 if(iSwapChain > 0) {
4598 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4599 if (hr == WINED3D_OK) {
4600 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4601 IWineD3DSwapChain_Release(swapChain);
4603 FIXME("(%p) Error getting display mode\n", This);
4606 /* Don't read the real display mode,
4607 but return the stored mode instead. X11 can't change the color
4608 depth, and some apps are pretty angry if they SetDisplayMode from
4609 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4611 Also don't relay to the swapchain because with ddraw it's possible
4612 that there isn't a swapchain at all */
4613 pMode->Width = This->ddraw_width;
4614 pMode->Height = This->ddraw_height;
4615 pMode->Format = This->ddraw_format;
4616 pMode->RefreshRate = 0;
4624 * Stateblock related functions
4627 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4628 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4629 IWineD3DStateBlock *stateblock;
4632 TRACE("(%p)\n", This);
4634 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4636 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4637 if (FAILED(hr)) return hr;
4639 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4640 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4641 This->isRecordingState = TRUE;
4643 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4648 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4649 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4651 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4653 if (!This->isRecordingState) {
4654 WARN("(%p) not recording! returning error\n", This);
4655 *ppStateBlock = NULL;
4656 return WINED3DERR_INVALIDCALL;
4659 for (i = 0; i <= WINEHIGHEST_RENDER_STATE >> 5; ++i)
4661 DWORD map = object->changed.renderState[i];
4662 for (j = 0; map; map >>= 1, ++j)
4664 if (!(map & 1)) continue;
4666 object->contained_render_states[object->num_contained_render_states++] = (i << 5) | j;
4670 for (i = 0; i <= HIGHEST_TRANSFORMSTATE >> 5; ++i)
4672 DWORD map = object->changed.transform[i];
4673 for (j = 0; map; map >>= 1, ++j)
4675 if (!(map & 1)) continue;
4677 object->contained_transform_states[object->num_contained_transform_states++] = (i << 5) | j;
4680 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4681 if(object->changed.vertexShaderConstantsF[i]) {
4682 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4683 object->num_contained_vs_consts_f++;
4686 for(i = 0; i < MAX_CONST_I; i++) {
4687 if (object->changed.vertexShaderConstantsI & (1 << i))
4689 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4690 object->num_contained_vs_consts_i++;
4693 for(i = 0; i < MAX_CONST_B; i++) {
4694 if (object->changed.vertexShaderConstantsB & (1 << i))
4696 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4697 object->num_contained_vs_consts_b++;
4700 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
4702 if (object->changed.pixelShaderConstantsF[i])
4704 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
4705 ++object->num_contained_ps_consts_f;
4708 for(i = 0; i < MAX_CONST_I; i++) {
4709 if (object->changed.pixelShaderConstantsI & (1 << i))
4711 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4712 object->num_contained_ps_consts_i++;
4715 for(i = 0; i < MAX_CONST_B; i++) {
4716 if (object->changed.pixelShaderConstantsB & (1 << i))
4718 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4719 object->num_contained_ps_consts_b++;
4722 for(i = 0; i < MAX_TEXTURES; i++) {
4723 DWORD map = object->changed.textureState[i];
4725 for(j = 0; map; map >>= 1, ++j)
4727 if (!(map & 1)) continue;
4729 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4730 object->contained_tss_states[object->num_contained_tss_states].state = j;
4731 ++object->num_contained_tss_states;
4734 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4735 DWORD map = object->changed.samplerState[i];
4737 for (j = 0; map; map >>= 1, ++j)
4739 if (!(map & 1)) continue;
4741 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4742 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4743 ++object->num_contained_sampler_states;
4747 *ppStateBlock = (IWineD3DStateBlock*) object;
4748 This->isRecordingState = FALSE;
4749 This->updateStateBlock = This->stateBlock;
4750 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4751 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4752 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4757 * Scene related functions
4759 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4760 /* At the moment we have no need for any functionality at the beginning
4762 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4763 TRACE("(%p)\n", This);
4766 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4767 return WINED3DERR_INVALIDCALL;
4769 This->inScene = TRUE;
4773 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4774 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4775 TRACE("(%p)\n", This);
4777 if(!This->inScene) {
4778 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4779 return WINED3DERR_INVALIDCALL;
4782 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
4783 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4785 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4789 This->inScene = FALSE;
4793 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4794 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4795 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4796 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4797 IWineD3DSwapChain *swapChain = NULL;
4799 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4801 TRACE("(%p) Presenting the frame\n", This);
4803 for(i = 0 ; i < swapchains ; i ++) {
4805 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4806 TRACE("presentinng chain %d, %p\n", i, swapChain);
4807 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4808 IWineD3DSwapChain_Release(swapChain);
4814 /* Not called from the VTable (internal subroutine) */
4815 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4816 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4817 float Z, DWORD Stencil) {
4818 GLbitfield glMask = 0;
4820 WINED3DRECT curRect;
4822 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4823 UINT drawable_width, drawable_height;
4824 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4825 IWineD3DSwapChainImpl *swapchain = NULL;
4826 struct wined3d_context *context;
4828 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4829 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4830 * for the cleared parts, and the untouched parts.
4832 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4833 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4834 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4835 * checking all this if the dest surface is in the drawable anyway.
4837 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4839 if(vp->X != 0 || vp->Y != 0 ||
4840 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4841 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4844 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4845 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4846 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4847 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4848 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4851 if(Count > 0 && pRects && (
4852 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4853 pRects[0].x2 < target->currentDesc.Width ||
4854 pRects[0].y2 < target->currentDesc.Height)) {
4855 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4862 context = ActivateContext(This, (IWineD3DSurface *)target, CTXUSAGE_CLEAR);
4864 target->get_drawable_size(context, &drawable_width, &drawable_height);
4868 /* Only set the values up once, as they are not changing */
4869 if (Flags & WINED3DCLEAR_STENCIL) {
4870 glClearStencil(Stencil);
4871 checkGLcall("glClearStencil");
4872 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4873 glStencilMask(0xFFFFFFFF);
4876 if (Flags & WINED3DCLEAR_ZBUFFER) {
4877 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4878 glDepthMask(GL_TRUE);
4880 checkGLcall("glClearDepth");
4881 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4882 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4884 if (vp->X != 0 || vp->Y != 0 ||
4885 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4886 surface_load_ds_location(This->stencilBufferTarget, context, location);
4888 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4889 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4890 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4891 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4892 surface_load_ds_location(This->stencilBufferTarget, context, location);
4894 else if (Count > 0 && pRects && (
4895 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4896 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4897 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4898 surface_load_ds_location(This->stencilBufferTarget, context, location);
4902 if (Flags & WINED3DCLEAR_TARGET) {
4903 TRACE("Clearing screen with glClear to color %x\n", Color);
4904 glClearColor(D3DCOLOR_R(Color),
4908 checkGLcall("glClearColor");
4910 /* Clear ALL colors! */
4911 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4912 glMask = glMask | GL_COLOR_BUFFER_BIT;
4915 vp_rect.left = vp->X;
4916 vp_rect.top = vp->Y;
4917 vp_rect.right = vp->X + vp->Width;
4918 vp_rect.bottom = vp->Y + vp->Height;
4919 if (!(Count > 0 && pRects)) {
4920 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4921 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4923 if (context->render_offscreen)
4925 glScissor(vp_rect.left, vp_rect.top,
4926 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4928 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4929 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4931 checkGLcall("glScissor");
4933 checkGLcall("glClear");
4935 /* Now process each rect in turn */
4936 for (i = 0; i < Count; i++) {
4937 /* Note gl uses lower left, width/height */
4938 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
4939 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4940 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4942 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4943 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4944 curRect.x1, (target->currentDesc.Height - curRect.y2),
4945 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4947 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4948 * The rectangle is not cleared, no error is returned, but further rectanlges are
4949 * still cleared if they are valid
4951 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4952 TRACE("Rectangle with negative dimensions, ignoring\n");
4956 if (context->render_offscreen)
4958 glScissor(curRect.x1, curRect.y1,
4959 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4961 glScissor(curRect.x1, drawable_height - curRect.y2,
4962 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4964 checkGLcall("glScissor");
4967 checkGLcall("glClear");
4971 /* Restore the old values (why..?) */
4972 if (Flags & WINED3DCLEAR_STENCIL) {
4973 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4975 if (Flags & WINED3DCLEAR_TARGET) {
4976 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4977 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4978 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4979 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4980 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4982 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4983 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4985 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
4987 if (Flags & WINED3DCLEAR_ZBUFFER) {
4988 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
4989 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4990 surface_modify_ds_location(This->stencilBufferTarget, location);
4995 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
4996 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
4999 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5005 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5006 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5007 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5008 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5010 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5011 Count, pRects, Flags, Color, Z, Stencil);
5013 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5014 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5015 /* TODO: What about depth stencil buffers without stencil bits? */
5016 return WINED3DERR_INVALIDCALL;
5019 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5026 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
5027 WINED3DPRIMITIVETYPE primitive_type)
5029 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5031 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
5033 This->updateStateBlock->changed.primitive_type = TRUE;
5034 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
5037 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
5038 WINED3DPRIMITIVETYPE *primitive_type)
5040 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5042 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
5044 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
5046 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
5049 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
5051 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5053 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
5055 if(!This->stateBlock->vertexDecl) {
5056 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5057 return WINED3DERR_INVALIDCALL;
5060 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5061 if(This->stateBlock->streamIsUP) {
5062 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5063 This->stateBlock->streamIsUP = FALSE;
5066 if(This->stateBlock->loadBaseVertexIndex != 0) {
5067 This->stateBlock->loadBaseVertexIndex = 0;
5068 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5070 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5071 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
5075 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
5077 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5079 IWineD3DBuffer *pIB;
5082 pIB = This->stateBlock->pIndexData;
5084 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5085 * without an index buffer set. (The first time at least...)
5086 * D3D8 simply dies, but I doubt it can do much harm to return
5087 * D3DERR_INVALIDCALL there as well. */
5088 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5089 return WINED3DERR_INVALIDCALL;
5092 if(!This->stateBlock->vertexDecl) {
5093 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5094 return WINED3DERR_INVALIDCALL;
5097 if(This->stateBlock->streamIsUP) {
5098 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5099 This->stateBlock->streamIsUP = FALSE;
5101 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
5103 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
5105 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
5111 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5112 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5113 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5116 drawPrimitive(iface, index_count, startIndex, idxStride,
5117 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
5122 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
5123 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5125 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5128 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
5129 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
5131 if(!This->stateBlock->vertexDecl) {
5132 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5133 return WINED3DERR_INVALIDCALL;
5136 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5137 vb = This->stateBlock->streamSource[0];
5138 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5139 if (vb) IWineD3DBuffer_Release(vb);
5140 This->stateBlock->streamOffset[0] = 0;
5141 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5142 This->stateBlock->streamIsUP = TRUE;
5143 This->stateBlock->loadBaseVertexIndex = 0;
5145 /* TODO: Only mark dirty if drawing from a different UP address */
5146 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5148 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
5150 /* MSDN specifies stream zero settings must be set to NULL */
5151 This->stateBlock->streamStride[0] = 0;
5152 This->stateBlock->streamSource[0] = NULL;
5154 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5155 * the new stream sources or use UP drawing again
5160 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
5161 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
5162 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
5165 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5169 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
5170 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5172 if(!This->stateBlock->vertexDecl) {
5173 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5174 return WINED3DERR_INVALIDCALL;
5177 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
5183 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5184 vb = This->stateBlock->streamSource[0];
5185 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
5186 if (vb) IWineD3DBuffer_Release(vb);
5187 This->stateBlock->streamIsUP = TRUE;
5188 This->stateBlock->streamOffset[0] = 0;
5189 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5191 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5192 This->stateBlock->baseVertexIndex = 0;
5193 This->stateBlock->loadBaseVertexIndex = 0;
5194 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5195 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5196 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5198 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
5200 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5201 This->stateBlock->streamSource[0] = NULL;
5202 This->stateBlock->streamStride[0] = 0;
5203 ib = This->stateBlock->pIndexData;
5205 IWineD3DBuffer_Release(ib);
5206 This->stateBlock->pIndexData = NULL;
5208 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5209 * SetStreamSource to specify a vertex buffer
5215 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5216 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
5218 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5220 /* Mark the state dirty until we have nicer tracking
5221 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5224 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5225 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5226 This->stateBlock->baseVertexIndex = 0;
5227 This->up_strided = DrawPrimStrideData;
5228 drawPrimitive(iface, vertex_count, 0, 0, NULL);
5229 This->up_strided = NULL;
5233 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5234 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
5235 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
5237 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5238 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
5240 /* Mark the state dirty until we have nicer tracking
5241 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5244 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5245 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5246 This->stateBlock->streamIsUP = TRUE;
5247 This->stateBlock->baseVertexIndex = 0;
5248 This->up_strided = DrawPrimStrideData;
5249 drawPrimitive(iface, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData);
5250 This->up_strided = NULL;
5254 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5255 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5256 * not callable by the app directly no parameter validation checks are needed here.
5258 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5259 WINED3DLOCKED_BOX src;
5260 WINED3DLOCKED_BOX dst;
5262 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5264 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5265 * dirtification to improve loading performance.
5267 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5268 if(FAILED(hr)) return hr;
5269 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5271 IWineD3DVolume_UnlockBox(pSourceVolume);
5275 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5277 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5279 IWineD3DVolume_UnlockBox(pSourceVolume);
5281 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5286 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5287 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5289 HRESULT hr = WINED3D_OK;
5290 WINED3DRESOURCETYPE sourceType;
5291 WINED3DRESOURCETYPE destinationType;
5294 /* TODO: think about moving the code into IWineD3DBaseTexture */
5296 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5298 /* verify that the source and destination textures aren't NULL */
5299 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5300 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5301 This, pSourceTexture, pDestinationTexture);
5302 hr = WINED3DERR_INVALIDCALL;
5305 if (pSourceTexture == pDestinationTexture) {
5306 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5307 This, pSourceTexture, pDestinationTexture);
5308 hr = WINED3DERR_INVALIDCALL;
5310 /* Verify that the source and destination textures are the same type */
5311 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5312 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5314 if (sourceType != destinationType) {
5315 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5317 hr = WINED3DERR_INVALIDCALL;
5320 /* check that both textures have the identical numbers of levels */
5321 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5322 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5323 hr = WINED3DERR_INVALIDCALL;
5326 if (WINED3D_OK == hr) {
5327 IWineD3DBaseTextureImpl *pDestImpl = (IWineD3DBaseTextureImpl *) pDestinationTexture;
5329 /* Make sure that the destination texture is loaded */
5330 pDestImpl->baseTexture.internal_preload(pDestinationTexture, SRGB_RGB);
5332 /* Update every surface level of the texture */
5333 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5335 switch (sourceType) {
5336 case WINED3DRTYPE_TEXTURE:
5338 IWineD3DSurface *srcSurface;
5339 IWineD3DSurface *destSurface;
5341 for (i = 0 ; i < levels ; ++i) {
5342 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5343 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5344 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5345 IWineD3DSurface_Release(srcSurface);
5346 IWineD3DSurface_Release(destSurface);
5347 if (WINED3D_OK != hr) {
5348 WARN("(%p) : Call to update surface failed\n", This);
5354 case WINED3DRTYPE_CUBETEXTURE:
5356 IWineD3DSurface *srcSurface;
5357 IWineD3DSurface *destSurface;
5358 WINED3DCUBEMAP_FACES faceType;
5360 for (i = 0 ; i < levels ; ++i) {
5361 /* Update each cube face */
5362 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5363 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5364 if (WINED3D_OK != hr) {
5365 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5367 TRACE("Got srcSurface %p\n", srcSurface);
5369 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5370 if (WINED3D_OK != hr) {
5371 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5373 TRACE("Got desrSurface %p\n", destSurface);
5375 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5376 IWineD3DSurface_Release(srcSurface);
5377 IWineD3DSurface_Release(destSurface);
5378 if (WINED3D_OK != hr) {
5379 WARN("(%p) : Call to update surface failed\n", This);
5387 case WINED3DRTYPE_VOLUMETEXTURE:
5389 IWineD3DVolume *srcVolume = NULL;
5390 IWineD3DVolume *destVolume = NULL;
5392 for (i = 0 ; i < levels ; ++i) {
5393 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5394 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5395 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5396 IWineD3DVolume_Release(srcVolume);
5397 IWineD3DVolume_Release(destVolume);
5398 if (WINED3D_OK != hr) {
5399 WARN("(%p) : Call to update volume failed\n", This);
5407 FIXME("(%p) : Unsupported source and destination type\n", This);
5408 hr = WINED3DERR_INVALIDCALL;
5415 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5416 IWineD3DSwapChain *swapChain;
5418 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5419 if(hr == WINED3D_OK) {
5420 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5421 IWineD3DSwapChain_Release(swapChain);
5426 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5427 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5428 IWineD3DBaseTextureImpl *texture;
5431 TRACE("(%p) : %p\n", This, pNumPasses);
5433 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5434 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5435 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5436 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5438 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5439 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5440 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5443 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5444 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5446 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5447 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5450 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5451 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5454 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5455 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5456 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5461 /* return a sensible default */
5464 TRACE("returning D3D_OK\n");
5468 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5472 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5473 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5474 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8
5475 || texture->resource.format_desc->format == WINED3DFMT_A8P8))
5477 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5482 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5483 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5486 PALETTEENTRY **palettes;
5488 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5490 if (PaletteNumber >= MAX_PALETTES) {
5491 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5492 return WINED3DERR_INVALIDCALL;
5495 if (PaletteNumber >= This->NumberOfPalettes) {
5496 NewSize = This->NumberOfPalettes;
5499 } while(PaletteNumber >= NewSize);
5500 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5502 ERR("Out of memory!\n");
5503 return E_OUTOFMEMORY;
5505 This->palettes = palettes;
5506 This->NumberOfPalettes = NewSize;
5509 if (!This->palettes[PaletteNumber]) {
5510 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5511 if (!This->palettes[PaletteNumber]) {
5512 ERR("Out of memory!\n");
5513 return E_OUTOFMEMORY;
5517 for (j = 0; j < 256; ++j) {
5518 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5519 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5520 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5521 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5523 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5524 TRACE("(%p) : returning\n", This);
5528 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5529 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5531 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5532 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5533 /* What happens in such situation isn't documented; Native seems to silently abort
5534 on such conditions. Return Invalid Call. */
5535 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5536 return WINED3DERR_INVALIDCALL;
5538 for (j = 0; j < 256; ++j) {
5539 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5540 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5541 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5542 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5544 TRACE("(%p) : returning\n", This);
5548 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5549 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5550 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5551 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5552 (tested with reference rasterizer). Return Invalid Call. */
5553 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5554 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5555 return WINED3DERR_INVALIDCALL;
5557 /*TODO: stateblocks */
5558 if (This->currentPalette != PaletteNumber) {
5559 This->currentPalette = PaletteNumber;
5560 dirtify_p8_texture_samplers(This);
5562 TRACE("(%p) : returning\n", This);
5566 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5567 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5568 if (PaletteNumber == NULL) {
5569 WARN("(%p) : returning Invalid Call\n", This);
5570 return WINED3DERR_INVALIDCALL;
5572 /*TODO: stateblocks */
5573 *PaletteNumber = This->currentPalette;
5574 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5578 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5579 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5583 FIXME("(%p) : stub\n", This);
5587 This->softwareVertexProcessing = bSoftware;
5592 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5593 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5597 FIXME("(%p) : stub\n", This);
5600 return This->softwareVertexProcessing;
5604 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5605 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5606 IWineD3DSwapChain *swapChain;
5609 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5611 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5612 if(hr == WINED3D_OK){
5613 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5614 IWineD3DSwapChain_Release(swapChain);
5616 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5622 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5623 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5625 if(nSegments != 0.0f) {
5628 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5635 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5636 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5640 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5646 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5647 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5648 /** TODO: remove casts to IWineD3DSurfaceImpl
5649 * NOTE: move code to surface to accomplish this
5650 ****************************************/
5651 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5652 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)pDestinationSurface;
5653 int srcWidth, srcHeight;
5654 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5655 WINED3DFORMAT destFormat, srcFormat;
5657 int srcLeft, destLeft, destTop;
5658 WINED3DPOOL srcPool, destPool;
5660 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5661 const struct GlPixelFormatDesc *src_format_desc, *dst_format_desc;
5665 CONVERT_TYPES convert = NO_CONVERSION;
5667 WINED3DSURFACE_DESC winedesc;
5669 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5671 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5672 srcSurfaceWidth = winedesc.width;
5673 srcSurfaceHeight = winedesc.height;
5674 srcPool = winedesc.pool;
5675 srcFormat = winedesc.format;
5677 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5678 destSurfaceWidth = winedesc.width;
5679 destSurfaceHeight = winedesc.height;
5680 destPool = winedesc.pool;
5681 destFormat = winedesc.format;
5682 destSize = winedesc.size;
5684 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5685 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5686 return WINED3DERR_INVALIDCALL;
5689 /* This call loads the opengl surface directly, instead of copying the surface to the
5690 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5691 * copy in sysmem and use regular surface loading.
5693 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5694 if(convert != NO_CONVERSION) {
5695 return IWineD3DSurface_BltFast(pDestinationSurface,
5696 pDestPoint ? pDestPoint->x : 0,
5697 pDestPoint ? pDestPoint->y : 0,
5698 pSourceSurface, pSourceRect, 0);
5701 if (destFormat == WINED3DFMT_UNKNOWN) {
5702 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5703 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5705 /* Get the update surface description */
5706 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5709 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
5712 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5713 checkGLcall("glActiveTextureARB");
5716 /* Make sure the surface is loaded and up to date */
5717 surface_internal_preload(pDestinationSurface, SRGB_RGB);
5718 IWineD3DSurface_BindTexture(pDestinationSurface, FALSE);
5720 src_format_desc = ((IWineD3DSurfaceImpl *)pSrcSurface)->resource.format_desc;
5721 dst_format_desc = dst_impl->resource.format_desc;
5723 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5724 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5725 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5726 srcLeft = pSourceRect ? pSourceRect->left : 0;
5727 destLeft = pDestPoint ? pDestPoint->x : 0;
5728 destTop = pDestPoint ? pDestPoint->y : 0;
5731 /* This function doesn't support compressed textures
5732 the pitch is just bytesPerPixel * width */
5733 if(srcWidth != srcSurfaceWidth || srcLeft ){
5734 rowoffset = srcSurfaceWidth * src_format_desc->byte_count;
5735 offset += srcLeft * src_format_desc->byte_count;
5736 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5738 /* TODO DXT formats */
5740 if(pSourceRect != NULL && pSourceRect->top != 0){
5741 offset += pSourceRect->top * srcSurfaceWidth * src_format_desc->byte_count;
5743 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5744 This, dst_impl->texture_level, destLeft, destTop, srcWidth, srcHeight, dst_format_desc->glFormat,
5745 dst_format_desc->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5748 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5750 /* need to lock the surface to get the data */
5751 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5756 /* TODO: Cube and volume support */
5758 /* not a whole row so we have to do it a line at a time */
5761 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5762 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5764 for (j = destTop; j < (srcHeight + destTop); ++j)
5766 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, j,
5767 srcWidth, 1, dst_format_desc->glFormat, dst_format_desc->glType,data);
5771 } else { /* Full width, so just write out the whole texture */
5772 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5774 if (dst_format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
5776 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth)
5778 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across. */
5779 FIXME("Updating part of a compressed texture is not supported.\n");
5781 if (destFormat != srcFormat)
5783 FIXME("Updating mixed format compressed textures is not supported.\n");
5787 GL_EXTCALL(glCompressedTexImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5788 dst_format_desc->glInternal, srcWidth, srcHeight, 0, destSize, data));
5793 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, destLeft, destTop,
5794 srcWidth, srcHeight, dst_format_desc->glFormat, dst_format_desc->glType, data);
5797 checkGLcall("glTexSubImage2D");
5801 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5802 sampler = This->rev_tex_unit_map[0];
5803 if (sampler != WINED3D_UNMAPPED_STAGE)
5805 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5811 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5812 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5813 struct WineD3DRectPatch *patch;
5814 GLenum old_primitive_type;
5818 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5820 if(!(Handle || pRectPatchInfo)) {
5821 /* TODO: Write a test for the return value, thus the FIXME */
5822 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5823 return WINED3DERR_INVALIDCALL;
5827 i = PATCHMAP_HASHFUNC(Handle);
5829 LIST_FOR_EACH(e, &This->patches[i]) {
5830 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5831 if(patch->Handle == Handle) {
5838 TRACE("Patch does not exist. Creating a new one\n");
5839 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5840 patch->Handle = Handle;
5841 list_add_head(&This->patches[i], &patch->entry);
5843 TRACE("Found existing patch %p\n", patch);
5846 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5847 * attributes we have to tesselate, read back, and draw. This needs a patch
5848 * management structure instance. Create one.
5850 * A possible improvement is to check if a vertex shader is used, and if not directly
5853 FIXME("Drawing an uncached patch. This is slow\n");
5854 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5857 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5858 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5859 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5861 TRACE("Tesselation density or patch info changed, retesselating\n");
5863 if(pRectPatchInfo) {
5864 patch->RectPatchInfo = *pRectPatchInfo;
5866 patch->numSegs[0] = pNumSegs[0];
5867 patch->numSegs[1] = pNumSegs[1];
5868 patch->numSegs[2] = pNumSegs[2];
5869 patch->numSegs[3] = pNumSegs[3];
5871 hr = tesselate_rectpatch(This, patch);
5873 WARN("Patch tesselation failed\n");
5875 /* Do not release the handle to store the params of the patch */
5877 HeapFree(GetProcessHeap(), 0, patch);
5883 This->currentPatch = patch;
5884 old_primitive_type = This->stateBlock->gl_primitive_type;
5885 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5886 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5887 This->stateBlock->gl_primitive_type = old_primitive_type;
5888 This->currentPatch = NULL;
5890 /* Destroy uncached patches */
5892 HeapFree(GetProcessHeap(), 0, patch->mem);
5893 HeapFree(GetProcessHeap(), 0, patch);
5898 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5899 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5900 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5901 FIXME("(%p) : Stub\n", This);
5905 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5906 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5908 struct WineD3DRectPatch *patch;
5910 TRACE("(%p) Handle(%d)\n", This, Handle);
5912 i = PATCHMAP_HASHFUNC(Handle);
5913 LIST_FOR_EACH(e, &This->patches[i]) {
5914 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5915 if(patch->Handle == Handle) {
5916 TRACE("Deleting patch %p\n", patch);
5917 list_remove(&patch->entry);
5918 HeapFree(GetProcessHeap(), 0, patch->mem);
5919 HeapFree(GetProcessHeap(), 0, patch);
5924 /* TODO: Write a test for the return value */
5925 FIXME("Attempt to destroy nonexistent patch\n");
5926 return WINED3DERR_INVALIDCALL;
5929 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5931 IWineD3DSwapChain *swapchain;
5933 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5934 if (SUCCEEDED(hr)) {
5935 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5942 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface,
5943 const WINED3DRECT *rect, const float color[4])
5945 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5946 struct wined3d_context *context;
5947 IWineD3DSwapChain *swapchain;
5949 swapchain = get_swapchain(surface);
5953 TRACE("Surface %p is onscreen\n", surface);
5955 context = ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
5957 context_bind_fbo(context, GL_FRAMEBUFFER_EXT, NULL);
5958 buffer = surface_get_gl_buffer(surface, swapchain);
5959 glDrawBuffer(buffer);
5960 checkGLcall("glDrawBuffer()");
5962 TRACE("Surface %p is offscreen\n", surface);
5964 context = ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
5966 context_bind_fbo(context, GL_FRAMEBUFFER_EXT, &context->dst_fbo);
5967 context_attach_surface_fbo(context, GL_FRAMEBUFFER_EXT, 0, surface);
5968 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER_EXT, NULL, FALSE);
5972 glEnable(GL_SCISSOR_TEST);
5974 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5976 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5977 rect->x2 - rect->x1, rect->y2 - rect->y1);
5979 checkGLcall("glScissor");
5980 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5982 glDisable(GL_SCISSOR_TEST);
5984 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5986 glDisable(GL_BLEND);
5987 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
5989 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5990 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5992 glClearColor(color[0], color[1], color[2], color[3]);
5993 glClear(GL_COLOR_BUFFER_BIT);
5994 checkGLcall("glClear");
5996 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5997 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5998 glDrawBuffer(GL_BACK);
5999 checkGLcall("glDrawBuffer()");
6005 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6006 unsigned int r, g, b, a;
6009 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6010 destfmt == WINED3DFMT_R8G8B8)
6013 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6015 a = (color & 0xff000000) >> 24;
6016 r = (color & 0x00ff0000) >> 16;
6017 g = (color & 0x0000ff00) >> 8;
6018 b = (color & 0x000000ff) >> 0;
6022 case WINED3DFMT_R5G6B5:
6023 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6030 TRACE("Returning %08x\n", ret);
6033 case WINED3DFMT_X1R5G5B5:
6034 case WINED3DFMT_A1R5G5B5:
6043 TRACE("Returning %08x\n", ret);
6046 case WINED3DFMT_A8_UNORM:
6047 TRACE("Returning %08x\n", a);
6050 case WINED3DFMT_X4R4G4B4:
6051 case WINED3DFMT_A4R4G4B4:
6060 TRACE("Returning %08x\n", ret);
6063 case WINED3DFMT_R3G3B2:
6070 TRACE("Returning %08x\n", ret);
6073 case WINED3DFMT_X8B8G8R8:
6074 case WINED3DFMT_R8G8B8A8_UNORM:
6079 TRACE("Returning %08x\n", ret);
6082 case WINED3DFMT_A2R10G10B10:
6084 r = (r * 1024) / 256;
6085 g = (g * 1024) / 256;
6086 b = (b * 1024) / 256;
6091 TRACE("Returning %08x\n", ret);
6094 case WINED3DFMT_R10G10B10A2_UNORM:
6096 r = (r * 1024) / 256;
6097 g = (g * 1024) / 256;
6098 b = (b * 1024) / 256;
6103 TRACE("Returning %08x\n", ret);
6107 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6112 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6113 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6114 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6116 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6118 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6119 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6120 return WINED3DERR_INVALIDCALL;
6123 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6124 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
6125 color_fill_fbo(iface, pSurface, pRect, c);
6128 /* Just forward this to the DirectDraw blitting engine */
6129 memset(&BltFx, 0, sizeof(BltFx));
6130 BltFx.dwSize = sizeof(BltFx);
6131 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format_desc->format);
6132 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6133 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
6137 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
6138 IWineD3DRendertargetView *rendertarget_view, const float color[4])
6140 IWineD3DResource *resource;
6141 IWineD3DSurface *surface;
6144 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
6147 ERR("Failed to get resource, hr %#x\n", hr);
6151 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
6153 FIXME("Only supported on surface resources\n");
6154 IWineD3DResource_Release(resource);
6158 surface = (IWineD3DSurface *)resource;
6160 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6162 color_fill_fbo(iface, surface, NULL, color);
6169 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
6171 c = ((DWORD)(color[2] * 255.0f));
6172 c |= ((DWORD)(color[1] * 255.0f)) << 8;
6173 c |= ((DWORD)(color[0] * 255.0f)) << 16;
6174 c |= ((DWORD)(color[3] * 255.0f)) << 24;
6176 /* Just forward this to the DirectDraw blitting engine */
6177 memset(&BltFx, 0, sizeof(BltFx));
6178 BltFx.dwSize = sizeof(BltFx);
6179 BltFx.u5.dwFillColor = argb_to_fmt(c, ((IWineD3DSurfaceImpl *)surface)->resource.format_desc->format);
6180 hr = IWineD3DSurface_Blt(surface, NULL, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
6183 ERR("Blt failed, hr %#x\n", hr);
6187 IWineD3DResource_Release(resource);
6190 /* rendertarget and depth stencil functions */
6191 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6194 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6195 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6196 return WINED3DERR_INVALIDCALL;
6199 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6200 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6201 /* Note inc ref on returned surface */
6202 if(*ppRenderTarget != NULL)
6203 IWineD3DSurface_AddRef(*ppRenderTarget);
6207 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6208 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6209 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6210 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6211 IWineD3DSwapChainImpl *Swapchain;
6214 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6216 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6217 if(hr != WINED3D_OK) {
6218 ERR("Can't get the swapchain\n");
6222 /* Make sure to release the swapchain */
6223 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6225 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6226 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6227 return WINED3DERR_INVALIDCALL;
6229 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6230 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6231 return WINED3DERR_INVALIDCALL;
6234 if(Swapchain->frontBuffer != Front) {
6235 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6237 if(Swapchain->frontBuffer)
6239 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6240 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags &= ~SFLAG_SWAPCHAIN;
6242 Swapchain->frontBuffer = Front;
6244 if(Swapchain->frontBuffer) {
6245 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6246 ((IWineD3DSurfaceImpl *)Swapchain->frontBuffer)->Flags |= SFLAG_SWAPCHAIN;
6250 if(Back && !Swapchain->backBuffer) {
6251 /* We need memory for the back buffer array - only one back buffer this way */
6252 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6253 if(!Swapchain->backBuffer) {
6254 ERR("Out of memory\n");
6255 return E_OUTOFMEMORY;
6259 if(Swapchain->backBuffer[0] != Back) {
6260 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6262 /* What to do about the context here in the case of multithreading? Not sure.
6263 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6265 WARN("No active context?\n");
6268 if(!Swapchain->backBuffer[0]) {
6269 /* GL was told to draw to the front buffer at creation,
6272 glDrawBuffer(GL_BACK);
6273 checkGLcall("glDrawBuffer(GL_BACK)");
6274 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6275 Swapchain->presentParms.BackBufferCount = 1;
6277 /* That makes problems - disable for now */
6278 /* glDrawBuffer(GL_FRONT); */
6279 checkGLcall("glDrawBuffer(GL_FRONT)");
6280 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6281 Swapchain->presentParms.BackBufferCount = 0;
6285 if(Swapchain->backBuffer[0])
6287 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6288 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags &= ~SFLAG_SWAPCHAIN;
6290 Swapchain->backBuffer[0] = Back;
6292 if(Swapchain->backBuffer[0]) {
6293 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6294 ((IWineD3DSurfaceImpl *)Swapchain->backBuffer[0])->Flags |= SFLAG_SWAPCHAIN;
6296 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6297 Swapchain->backBuffer = NULL;
6305 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6306 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6307 *ppZStencilSurface = This->stencilBufferTarget;
6308 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6310 if(*ppZStencilSurface != NULL) {
6311 /* Note inc ref on returned surface */
6312 IWineD3DSurface_AddRef(*ppZStencilSurface);
6315 return WINED3DERR_NOTFOUND;
6319 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6320 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6323 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6324 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6325 struct wined3d_context *context;
6327 POINT offset = {0, 0};
6329 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6330 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6331 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6332 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6335 case WINED3DTEXF_LINEAR:
6336 gl_filter = GL_LINEAR;
6340 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6341 case WINED3DTEXF_NONE:
6342 case WINED3DTEXF_POINT:
6343 gl_filter = GL_NEAREST;
6347 /* Attach src surface to src fbo */
6348 src_swapchain = get_swapchain(src_surface);
6349 dst_swapchain = get_swapchain(dst_surface);
6351 if (src_swapchain) context = ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6352 else if (dst_swapchain) context = ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6353 else context = ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6355 if (src_swapchain) {
6356 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6358 TRACE("Source surface %p is onscreen\n", src_surface);
6359 /* Make sure the drawable is up to date. In the offscreen case
6360 * attach_surface_fbo() implicitly takes care of this. */
6361 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6363 if(buffer == GL_FRONT) {
6366 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6367 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6368 h = windowsize.bottom - windowsize.top;
6369 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6370 src_rect->y1 = offset.y + h - src_rect->y1;
6371 src_rect->y2 = offset.y + h - src_rect->y2;
6373 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6374 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6378 context_bind_fbo(context, GL_READ_FRAMEBUFFER_EXT, NULL);
6379 glReadBuffer(buffer);
6380 checkGLcall("glReadBuffer()");
6382 TRACE("Source surface %p is offscreen\n", src_surface);
6384 context_bind_fbo(context, GL_READ_FRAMEBUFFER_EXT, &context->src_fbo);
6385 context_attach_surface_fbo(context, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6386 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6387 checkGLcall("glReadBuffer()");
6388 context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER_EXT, NULL, FALSE);
6392 /* Attach dst surface to dst fbo */
6393 if (dst_swapchain) {
6394 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6396 TRACE("Destination surface %p is onscreen\n", dst_surface);
6397 /* Make sure the drawable is up to date. In the offscreen case
6398 * attach_surface_fbo() implicitly takes care of this. */
6399 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6401 if(buffer == GL_FRONT) {
6404 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6405 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6406 h = windowsize.bottom - windowsize.top;
6407 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6408 dst_rect->y1 = offset.y + h - dst_rect->y1;
6409 dst_rect->y2 = offset.y + h - dst_rect->y2;
6411 /* Screen coords = window coords, surface height = window height */
6412 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6413 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6417 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER_EXT, NULL);
6418 glDrawBuffer(buffer);
6419 checkGLcall("glDrawBuffer()");
6421 TRACE("Destination surface %p is offscreen\n", dst_surface);
6424 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER_EXT, &context->dst_fbo);
6425 context_attach_surface_fbo(context, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6426 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6427 checkGLcall("glDrawBuffer()");
6428 context_attach_depth_stencil_fbo(context, GL_DRAW_FRAMEBUFFER_EXT, NULL, FALSE);
6430 glDisable(GL_SCISSOR_TEST);
6431 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6434 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6435 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6436 checkGLcall("glBlitFramebuffer()");
6438 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6439 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6440 checkGLcall("glBlitFramebuffer()");
6443 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6445 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6446 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6447 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6448 glDrawBuffer(GL_BACK);
6449 checkGLcall("glDrawBuffer()");
6454 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6455 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6456 WINED3DVIEWPORT viewport;
6458 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6460 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6461 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6462 This, RenderTargetIndex, GL_LIMITS(buffers));
6463 return WINED3DERR_INVALIDCALL;
6466 /* MSDN says that null disables the render target
6467 but a device must always be associated with a render target
6468 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6470 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6471 FIXME("Trying to set render target 0 to NULL\n");
6472 return WINED3DERR_INVALIDCALL;
6474 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6475 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);
6476 return WINED3DERR_INVALIDCALL;
6479 /* If we are trying to set what we already have, don't bother */
6480 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6481 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6484 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6485 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6486 This->render_targets[RenderTargetIndex] = pRenderTarget;
6488 /* Render target 0 is special */
6489 if(RenderTargetIndex == 0) {
6490 /* Finally, reset the viewport as the MSDN states. */
6491 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6492 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6495 viewport.MaxZ = 1.0f;
6496 viewport.MinZ = 0.0f;
6497 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6502 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6503 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6504 HRESULT hr = WINED3D_OK;
6505 IWineD3DSurface *tmp;
6507 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6509 if (pNewZStencil == This->stencilBufferTarget) {
6510 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6512 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6513 * depending on the renter target implementation being used.
6514 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6515 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6516 * stencil buffer and incur an extra memory overhead
6517 ******************************************************/
6519 if (This->stencilBufferTarget) {
6520 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6521 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6522 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6524 struct wined3d_context *context = ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6525 surface_load_ds_location(This->stencilBufferTarget, context, SFLAG_DS_OFFSCREEN);
6526 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6530 tmp = This->stencilBufferTarget;
6531 This->stencilBufferTarget = pNewZStencil;
6532 /* should we be calling the parent or the wined3d surface? */
6533 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6534 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6537 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6538 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6539 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6540 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6541 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6548 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6549 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6550 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6551 /* TODO: the use of Impl is deprecated. */
6552 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6553 WINED3DLOCKED_RECT lockedRect;
6555 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6557 /* some basic validation checks */
6558 if(This->cursorTexture) {
6559 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6561 glDeleteTextures(1, &This->cursorTexture);
6563 This->cursorTexture = 0;
6566 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6567 This->haveHardwareCursor = TRUE;
6569 This->haveHardwareCursor = FALSE;
6572 WINED3DLOCKED_RECT rect;
6574 /* MSDN: Cursor must be A8R8G8B8 */
6575 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format_desc->format)
6577 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6578 return WINED3DERR_INVALIDCALL;
6581 /* MSDN: Cursor must be smaller than the display mode */
6582 if(pSur->currentDesc.Width > This->ddraw_width ||
6583 pSur->currentDesc.Height > This->ddraw_height) {
6584 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);
6585 return WINED3DERR_INVALIDCALL;
6588 if (!This->haveHardwareCursor) {
6589 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6591 /* Do not store the surface's pointer because the application may
6592 * release it after setting the cursor image. Windows doesn't
6593 * addref the set surface, so we can't do this either without
6594 * creating circular refcount dependencies. Copy out the gl texture
6597 This->cursorWidth = pSur->currentDesc.Width;
6598 This->cursorHeight = pSur->currentDesc.Height;
6599 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6601 const struct GlPixelFormatDesc *glDesc = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION);
6602 char *mem, *bits = rect.pBits;
6603 GLint intfmt = glDesc->glInternal;
6604 GLint format = glDesc->glFormat;
6605 GLint type = glDesc->glType;
6606 INT height = This->cursorHeight;
6607 INT width = This->cursorWidth;
6608 INT bpp = glDesc->byte_count;
6612 /* Reformat the texture memory (pitch and width can be
6614 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6615 for(i = 0; i < height; i++)
6616 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6617 IWineD3DSurface_UnlockRect(pCursorBitmap);
6619 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6623 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6624 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6625 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6628 /* Make sure that a proper texture unit is selected */
6629 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6630 checkGLcall("glActiveTextureARB");
6631 sampler = This->rev_tex_unit_map[0];
6632 if (sampler != WINED3D_UNMAPPED_STAGE)
6634 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6636 /* Create a new cursor texture */
6637 glGenTextures(1, &This->cursorTexture);
6638 checkGLcall("glGenTextures");
6639 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6640 checkGLcall("glBindTexture");
6641 /* Copy the bitmap memory into the cursor texture */
6642 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6643 HeapFree(GetProcessHeap(), 0, mem);
6644 checkGLcall("glTexImage2D");
6646 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6647 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6648 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6655 FIXME("A cursor texture was not returned.\n");
6656 This->cursorTexture = 0;
6661 /* Draw a hardware cursor */
6662 ICONINFO cursorInfo;
6664 /* Create and clear maskBits because it is not needed for
6665 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6667 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6668 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6669 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6670 WINED3DLOCK_NO_DIRTY_UPDATE |
6671 WINED3DLOCK_READONLY
6673 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6674 pSur->currentDesc.Height);
6676 cursorInfo.fIcon = FALSE;
6677 cursorInfo.xHotspot = XHotSpot;
6678 cursorInfo.yHotspot = YHotSpot;
6679 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6680 pSur->currentDesc.Height, 1,
6682 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6683 pSur->currentDesc.Height, 1,
6684 32, lockedRect.pBits);
6685 IWineD3DSurface_UnlockRect(pCursorBitmap);
6686 /* Create our cursor and clean up. */
6687 cursor = CreateIconIndirect(&cursorInfo);
6689 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6690 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6691 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6692 This->hardwareCursor = cursor;
6693 HeapFree(GetProcessHeap(), 0, maskBits);
6697 This->xHotSpot = XHotSpot;
6698 This->yHotSpot = YHotSpot;
6702 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6703 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6704 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6706 This->xScreenSpace = XScreenSpace;
6707 This->yScreenSpace = YScreenSpace;
6713 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6714 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6715 BOOL oldVisible = This->bCursorVisible;
6718 TRACE("(%p) : visible(%d)\n", This, bShow);
6721 * When ShowCursor is first called it should make the cursor appear at the OS's last
6722 * known cursor position. Because of this, some applications just repetitively call
6723 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6726 This->xScreenSpace = pt.x;
6727 This->yScreenSpace = pt.y;
6729 if (This->haveHardwareCursor) {
6730 This->bCursorVisible = bShow;
6732 SetCursor(This->hardwareCursor);
6738 if (This->cursorTexture)
6739 This->bCursorVisible = bShow;
6745 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6746 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6747 IWineD3DResourceImpl *resource;
6748 TRACE("(%p) : state (%u)\n", This, This->state);
6750 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6751 switch (This->state) {
6754 case WINED3DERR_DEVICELOST:
6756 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6757 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6758 return WINED3DERR_DEVICENOTRESET;
6760 return WINED3DERR_DEVICELOST;
6762 case WINED3DERR_DRIVERINTERNALERROR:
6763 return WINED3DERR_DRIVERINTERNALERROR;
6767 return WINED3DERR_DRIVERINTERNALERROR;
6770 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6771 TRACE("checking resource %p for eviction\n", resource);
6772 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6773 TRACE("Evicting %p\n", resource);
6774 IWineD3DResource_UnLoad(resource);
6776 IWineD3DResource_Release(resource);
6780 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6781 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6782 TRACE("(%p)\n", This);
6784 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6788 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6790 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6792 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6793 if(surface->Flags & SFLAG_DIBSECTION) {
6794 /* Release the DC */
6795 SelectObject(surface->hDC, surface->dib.holdbitmap);
6796 DeleteDC(surface->hDC);
6797 /* Release the DIB section */
6798 DeleteObject(surface->dib.DIBsection);
6799 surface->dib.bitmap_data = NULL;
6800 surface->resource.allocatedMemory = NULL;
6801 surface->Flags &= ~SFLAG_DIBSECTION;
6803 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6804 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6805 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
6806 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
6807 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6808 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6810 surface->pow2Width = surface->pow2Height = 1;
6811 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6812 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6814 surface->glRect.left = 0;
6815 surface->glRect.top = 0;
6816 surface->glRect.right = surface->pow2Width;
6817 surface->glRect.bottom = surface->pow2Height;
6819 if (surface->texture_name)
6821 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6823 glDeleteTextures(1, &surface->texture_name);
6825 surface->texture_name = 0;
6826 surface->Flags &= ~SFLAG_CLIENT;
6828 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6829 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6830 surface->Flags |= SFLAG_NONPOW2;
6832 surface->Flags &= ~SFLAG_NONPOW2;
6834 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6835 surface->resource.allocatedMemory = NULL;
6836 surface->resource.heapMemory = NULL;
6837 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6838 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
6839 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
6840 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
6842 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
6846 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6847 TRACE("Unloading resource %p\n", resource);
6848 IWineD3DResource_UnLoad(resource);
6849 IWineD3DResource_Release(resource);
6853 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6856 WINED3DDISPLAYMODE m;
6859 /* All Windowed modes are supported, as is leaving the current mode */
6860 if(pp->Windowed) return TRUE;
6861 if(!pp->BackBufferWidth) return TRUE;
6862 if(!pp->BackBufferHeight) return TRUE;
6864 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
6865 for(i = 0; i < count; i++) {
6866 memset(&m, 0, sizeof(m));
6867 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
6869 ERR("EnumAdapterModes failed\n");
6871 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6872 /* Mode found, it is supported */
6876 /* Mode not found -> not supported */
6880 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6882 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6884 IWineD3DBaseShaderImpl *shader;
6886 ActivateContext(This, NULL, CTXUSAGE_RESOURCELOAD);
6888 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6889 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6890 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6894 if(This->depth_blt_texture) {
6895 glDeleteTextures(1, &This->depth_blt_texture);
6896 This->depth_blt_texture = 0;
6898 if (This->depth_blt_rb) {
6899 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
6900 This->depth_blt_rb = 0;
6901 This->depth_blt_rb_w = 0;
6902 This->depth_blt_rb_h = 0;
6906 This->blitter->free_private(iface);
6907 This->frag_pipe->free_private(iface);
6908 This->shader_backend->shader_free_private(iface);
6911 for (i = 0; i < GL_LIMITS(textures); i++) {
6912 /* Textures are recreated below */
6913 glDeleteTextures(1, &This->dummyTextureName[i]);
6914 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
6915 This->dummyTextureName[i] = 0;
6919 while(This->numContexts) {
6920 DestroyContext(This, This->contexts[0]);
6922 HeapFree(GetProcessHeap(), 0, swapchain->context);
6923 swapchain->context = NULL;
6924 swapchain->num_contexts = 0;
6927 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6928 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6929 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6931 IWineD3DSurfaceImpl *target;
6933 /* Recreate the primary swapchain's context */
6934 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6935 if(swapchain->backBuffer) {
6936 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
6938 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
6940 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
6941 &swapchain->presentParms);
6942 swapchain->num_contexts = 1;
6944 create_dummy_textures(This);
6946 hr = This->shader_backend->shader_alloc_private(iface);
6948 ERR("Failed to recreate shader private data\n");
6951 hr = This->frag_pipe->alloc_private(iface);
6953 TRACE("Fragment pipeline private data couldn't be allocated\n");
6956 hr = This->blitter->alloc_private(iface);
6958 TRACE("Blitter private data couldn't be allocated\n");
6965 This->blitter->free_private(iface);
6966 This->frag_pipe->free_private(iface);
6967 This->shader_backend->shader_free_private(iface);
6971 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6973 IWineD3DSwapChainImpl *swapchain;
6975 BOOL DisplayModeChanged = FALSE;
6976 WINED3DDISPLAYMODE mode;
6977 TRACE("(%p)\n", This);
6979 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6981 ERR("Failed to get the first implicit swapchain\n");
6985 if(!is_display_mode_supported(This, pPresentationParameters)) {
6986 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6987 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6988 pPresentationParameters->BackBufferHeight);
6989 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6990 return WINED3DERR_INVALIDCALL;
6993 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6994 * on an existing gl context, so there's no real need for recreation.
6996 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6998 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7000 TRACE("New params:\n");
7001 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7002 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7003 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7004 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7005 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7006 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7007 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7008 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7009 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7010 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7011 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7012 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7013 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7015 /* No special treatment of these parameters. Just store them */
7016 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7017 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7018 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7019 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7021 /* What to do about these? */
7022 if(pPresentationParameters->BackBufferCount != 0 &&
7023 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7024 ERR("Cannot change the back buffer count yet\n");
7026 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7027 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7028 ERR("Cannot change the back buffer format yet\n");
7030 if(pPresentationParameters->hDeviceWindow != NULL &&
7031 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7032 ERR("Cannot change the device window yet\n");
7034 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7037 TRACE("Creating the depth stencil buffer\n");
7039 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
7041 pPresentationParameters->BackBufferWidth,
7042 pPresentationParameters->BackBufferHeight,
7043 pPresentationParameters->AutoDepthStencilFormat,
7044 pPresentationParameters->MultiSampleType,
7045 pPresentationParameters->MultiSampleQuality,
7047 &This->auto_depth_stencil_buffer);
7050 ERR("Failed to create the depth stencil buffer\n");
7051 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7052 return WINED3DERR_INVALIDCALL;
7056 /* Reset the depth stencil */
7057 if (pPresentationParameters->EnableAutoDepthStencil)
7058 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7060 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7062 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7064 if(pPresentationParameters->Windowed) {
7065 mode.Width = swapchain->orig_width;
7066 mode.Height = swapchain->orig_height;
7067 mode.RefreshRate = 0;
7068 mode.Format = swapchain->presentParms.BackBufferFormat;
7070 mode.Width = pPresentationParameters->BackBufferWidth;
7071 mode.Height = pPresentationParameters->BackBufferHeight;
7072 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7073 mode.Format = swapchain->presentParms.BackBufferFormat;
7076 /* Should Width == 800 && Height == 0 set 800x600? */
7077 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7078 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7079 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7083 if(!pPresentationParameters->Windowed) {
7084 DisplayModeChanged = TRUE;
7086 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7087 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7089 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7090 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7091 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7093 if(This->auto_depth_stencil_buffer) {
7094 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7098 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7099 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7100 DisplayModeChanged) {
7102 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7104 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7105 if(swapchain->presentParms.Windowed) {
7106 /* switch from windowed to fs */
7107 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7108 pPresentationParameters->BackBufferWidth,
7109 pPresentationParameters->BackBufferHeight);
7111 /* Fullscreen -> fullscreen mode change */
7112 MoveWindow(swapchain->win_handle, 0, 0,
7113 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7116 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7117 /* Fullscreen -> windowed switch */
7118 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7120 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7121 } else if(!pPresentationParameters->Windowed) {
7122 DWORD style = This->style, exStyle = This->exStyle;
7123 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7124 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7125 * Reset to clear up their mess. Guild Wars also loses the device during that.
7129 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7130 pPresentationParameters->BackBufferWidth,
7131 pPresentationParameters->BackBufferHeight);
7132 This->style = style;
7133 This->exStyle = exStyle;
7136 TRACE("Resetting stateblock\n");
7137 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
7138 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
7140 /* Note: No parent needed for initial internal stateblock */
7141 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
7142 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7143 else TRACE("Created stateblock %p\n", This->stateBlock);
7144 This->updateStateBlock = This->stateBlock;
7145 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
7147 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7149 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7152 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7153 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7155 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7161 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7162 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7163 /** FIXME: always true at the moment **/
7164 if(!bEnableDialogs) {
7165 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7171 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7172 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7173 TRACE("(%p) : pParameters %p\n", This, pParameters);
7175 *pParameters = This->createParms;
7179 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7180 IWineD3DSwapChain *swapchain;
7182 TRACE("Relaying to swapchain\n");
7184 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7185 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7186 IWineD3DSwapChain_Release(swapchain);
7191 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7192 IWineD3DSwapChain *swapchain;
7194 TRACE("Relaying to swapchain\n");
7196 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7197 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7198 IWineD3DSwapChain_Release(swapchain);
7204 /** ********************************************************
7205 * Notification functions
7206 ** ********************************************************/
7207 /** This function must be called in the release of a resource when ref == 0,
7208 * the contents of resource must still be correct,
7209 * any handles to other resource held by the caller must be closed
7210 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7211 *****************************************************/
7212 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7214 TRACE("(%p) : Adding resource %p\n", This, resource);
7216 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7219 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7221 TRACE("(%p) : Removing resource %p\n", This, resource);
7223 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7226 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
7228 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7231 TRACE("(%p) : resource %p\n", This, resource);
7233 context_resource_released((IWineD3DDevice *)This, resource, type);
7236 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7237 case WINED3DRTYPE_SURFACE: {
7240 if (This->d3d_initialized)
7242 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7243 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7244 This->render_targets[i] = NULL;
7247 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7248 This->stencilBufferTarget = NULL;
7254 case WINED3DRTYPE_TEXTURE:
7255 case WINED3DRTYPE_CUBETEXTURE:
7256 case WINED3DRTYPE_VOLUMETEXTURE:
7257 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7258 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7259 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7260 This->stateBlock->textures[counter] = NULL;
7262 if (This->updateStateBlock != This->stateBlock ){
7263 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7264 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7265 This->updateStateBlock->textures[counter] = NULL;
7270 case WINED3DRTYPE_VOLUME:
7271 /* TODO: nothing really? */
7273 case WINED3DRTYPE_BUFFER:
7276 TRACE("Cleaning up stream pointers\n");
7278 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7279 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7280 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7282 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7283 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7284 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7285 This->updateStateBlock->streamSource[streamNumber] = 0;
7286 /* Set changed flag? */
7289 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) */
7290 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7291 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7292 This->stateBlock->streamSource[streamNumber] = 0;
7297 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7298 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7299 This->updateStateBlock->pIndexData = NULL;
7302 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7303 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
7304 This->stateBlock->pIndexData = NULL;
7311 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7316 /* Remove the resource from the resourceStore */
7317 device_resource_remove(This, resource);
7319 TRACE("Resource released\n");
7323 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7325 IWineD3DResourceImpl *resource, *cursor;
7327 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7329 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7330 TRACE("enumerating resource %p\n", resource);
7331 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7332 ret = pCallback((IWineD3DResource *) resource, pData);
7333 if(ret == S_FALSE) {
7334 TRACE("Canceling enumeration\n");
7341 /**********************************************************
7342 * IWineD3DDevice VTbl follows
7343 **********************************************************/
7345 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7347 /*** IUnknown methods ***/
7348 IWineD3DDeviceImpl_QueryInterface,
7349 IWineD3DDeviceImpl_AddRef,
7350 IWineD3DDeviceImpl_Release,
7351 /*** IWineD3DDevice methods ***/
7352 IWineD3DDeviceImpl_GetParent,
7353 /*** Creation methods**/
7354 IWineD3DDeviceImpl_CreateBuffer,
7355 IWineD3DDeviceImpl_CreateVertexBuffer,
7356 IWineD3DDeviceImpl_CreateIndexBuffer,
7357 IWineD3DDeviceImpl_CreateStateBlock,
7358 IWineD3DDeviceImpl_CreateSurface,
7359 IWineD3DDeviceImpl_CreateRendertargetView,
7360 IWineD3DDeviceImpl_CreateTexture,
7361 IWineD3DDeviceImpl_CreateVolumeTexture,
7362 IWineD3DDeviceImpl_CreateVolume,
7363 IWineD3DDeviceImpl_CreateCubeTexture,
7364 IWineD3DDeviceImpl_CreateQuery,
7365 IWineD3DDeviceImpl_CreateSwapChain,
7366 IWineD3DDeviceImpl_CreateVertexDeclaration,
7367 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7368 IWineD3DDeviceImpl_CreateVertexShader,
7369 IWineD3DDeviceImpl_CreatePixelShader,
7370 IWineD3DDeviceImpl_CreatePalette,
7371 /*** Odd functions **/
7372 IWineD3DDeviceImpl_Init3D,
7373 IWineD3DDeviceImpl_InitGDI,
7374 IWineD3DDeviceImpl_Uninit3D,
7375 IWineD3DDeviceImpl_UninitGDI,
7376 IWineD3DDeviceImpl_SetMultithreaded,
7377 IWineD3DDeviceImpl_EvictManagedResources,
7378 IWineD3DDeviceImpl_GetAvailableTextureMem,
7379 IWineD3DDeviceImpl_GetBackBuffer,
7380 IWineD3DDeviceImpl_GetCreationParameters,
7381 IWineD3DDeviceImpl_GetDeviceCaps,
7382 IWineD3DDeviceImpl_GetDirect3D,
7383 IWineD3DDeviceImpl_GetDisplayMode,
7384 IWineD3DDeviceImpl_SetDisplayMode,
7385 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7386 IWineD3DDeviceImpl_GetRasterStatus,
7387 IWineD3DDeviceImpl_GetSwapChain,
7388 IWineD3DDeviceImpl_Reset,
7389 IWineD3DDeviceImpl_SetDialogBoxMode,
7390 IWineD3DDeviceImpl_SetCursorProperties,
7391 IWineD3DDeviceImpl_SetCursorPosition,
7392 IWineD3DDeviceImpl_ShowCursor,
7393 IWineD3DDeviceImpl_TestCooperativeLevel,
7394 /*** Getters and setters **/
7395 IWineD3DDeviceImpl_SetClipPlane,
7396 IWineD3DDeviceImpl_GetClipPlane,
7397 IWineD3DDeviceImpl_SetClipStatus,
7398 IWineD3DDeviceImpl_GetClipStatus,
7399 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7400 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7401 IWineD3DDeviceImpl_SetDepthStencilSurface,
7402 IWineD3DDeviceImpl_GetDepthStencilSurface,
7403 IWineD3DDeviceImpl_SetGammaRamp,
7404 IWineD3DDeviceImpl_GetGammaRamp,
7405 IWineD3DDeviceImpl_SetIndices,
7406 IWineD3DDeviceImpl_GetIndices,
7407 IWineD3DDeviceImpl_SetBaseVertexIndex,
7408 IWineD3DDeviceImpl_GetBaseVertexIndex,
7409 IWineD3DDeviceImpl_SetLight,
7410 IWineD3DDeviceImpl_GetLight,
7411 IWineD3DDeviceImpl_SetLightEnable,
7412 IWineD3DDeviceImpl_GetLightEnable,
7413 IWineD3DDeviceImpl_SetMaterial,
7414 IWineD3DDeviceImpl_GetMaterial,
7415 IWineD3DDeviceImpl_SetNPatchMode,
7416 IWineD3DDeviceImpl_GetNPatchMode,
7417 IWineD3DDeviceImpl_SetPaletteEntries,
7418 IWineD3DDeviceImpl_GetPaletteEntries,
7419 IWineD3DDeviceImpl_SetPixelShader,
7420 IWineD3DDeviceImpl_GetPixelShader,
7421 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7422 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7423 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7424 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7425 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7426 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7427 IWineD3DDeviceImpl_SetRenderState,
7428 IWineD3DDeviceImpl_GetRenderState,
7429 IWineD3DDeviceImpl_SetRenderTarget,
7430 IWineD3DDeviceImpl_GetRenderTarget,
7431 IWineD3DDeviceImpl_SetFrontBackBuffers,
7432 IWineD3DDeviceImpl_SetSamplerState,
7433 IWineD3DDeviceImpl_GetSamplerState,
7434 IWineD3DDeviceImpl_SetScissorRect,
7435 IWineD3DDeviceImpl_GetScissorRect,
7436 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7437 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7438 IWineD3DDeviceImpl_SetStreamSource,
7439 IWineD3DDeviceImpl_GetStreamSource,
7440 IWineD3DDeviceImpl_SetStreamSourceFreq,
7441 IWineD3DDeviceImpl_GetStreamSourceFreq,
7442 IWineD3DDeviceImpl_SetTexture,
7443 IWineD3DDeviceImpl_GetTexture,
7444 IWineD3DDeviceImpl_SetTextureStageState,
7445 IWineD3DDeviceImpl_GetTextureStageState,
7446 IWineD3DDeviceImpl_SetTransform,
7447 IWineD3DDeviceImpl_GetTransform,
7448 IWineD3DDeviceImpl_SetVertexDeclaration,
7449 IWineD3DDeviceImpl_GetVertexDeclaration,
7450 IWineD3DDeviceImpl_SetVertexShader,
7451 IWineD3DDeviceImpl_GetVertexShader,
7452 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7453 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7454 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7455 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7456 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7457 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7458 IWineD3DDeviceImpl_SetViewport,
7459 IWineD3DDeviceImpl_GetViewport,
7460 IWineD3DDeviceImpl_MultiplyTransform,
7461 IWineD3DDeviceImpl_ValidateDevice,
7462 IWineD3DDeviceImpl_ProcessVertices,
7463 /*** State block ***/
7464 IWineD3DDeviceImpl_BeginStateBlock,
7465 IWineD3DDeviceImpl_EndStateBlock,
7466 /*** Scene management ***/
7467 IWineD3DDeviceImpl_BeginScene,
7468 IWineD3DDeviceImpl_EndScene,
7469 IWineD3DDeviceImpl_Present,
7470 IWineD3DDeviceImpl_Clear,
7471 IWineD3DDeviceImpl_ClearRendertargetView,
7473 IWineD3DDeviceImpl_SetPrimitiveType,
7474 IWineD3DDeviceImpl_GetPrimitiveType,
7475 IWineD3DDeviceImpl_DrawPrimitive,
7476 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7477 IWineD3DDeviceImpl_DrawPrimitiveUP,
7478 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7479 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7480 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7481 IWineD3DDeviceImpl_DrawRectPatch,
7482 IWineD3DDeviceImpl_DrawTriPatch,
7483 IWineD3DDeviceImpl_DeletePatch,
7484 IWineD3DDeviceImpl_ColorFill,
7485 IWineD3DDeviceImpl_UpdateTexture,
7486 IWineD3DDeviceImpl_UpdateSurface,
7487 IWineD3DDeviceImpl_GetFrontBufferData,
7488 /*** object tracking ***/
7489 IWineD3DDeviceImpl_EnumResources
7492 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7493 WINED3DRS_ALPHABLENDENABLE ,
7494 WINED3DRS_ALPHAFUNC ,
7495 WINED3DRS_ALPHAREF ,
7496 WINED3DRS_ALPHATESTENABLE ,
7498 WINED3DRS_COLORWRITEENABLE ,
7499 WINED3DRS_DESTBLEND ,
7500 WINED3DRS_DITHERENABLE ,
7501 WINED3DRS_FILLMODE ,
7502 WINED3DRS_FOGDENSITY ,
7504 WINED3DRS_FOGSTART ,
7505 WINED3DRS_LASTPIXEL ,
7506 WINED3DRS_SHADEMODE ,
7507 WINED3DRS_SRCBLEND ,
7508 WINED3DRS_STENCILENABLE ,
7509 WINED3DRS_STENCILFAIL ,
7510 WINED3DRS_STENCILFUNC ,
7511 WINED3DRS_STENCILMASK ,
7512 WINED3DRS_STENCILPASS ,
7513 WINED3DRS_STENCILREF ,
7514 WINED3DRS_STENCILWRITEMASK ,
7515 WINED3DRS_STENCILZFAIL ,
7516 WINED3DRS_TEXTUREFACTOR ,
7527 WINED3DRS_ZWRITEENABLE
7530 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7531 WINED3DTSS_ALPHAARG0 ,
7532 WINED3DTSS_ALPHAARG1 ,
7533 WINED3DTSS_ALPHAARG2 ,
7534 WINED3DTSS_ALPHAOP ,
7535 WINED3DTSS_BUMPENVLOFFSET ,
7536 WINED3DTSS_BUMPENVLSCALE ,
7537 WINED3DTSS_BUMPENVMAT00 ,
7538 WINED3DTSS_BUMPENVMAT01 ,
7539 WINED3DTSS_BUMPENVMAT10 ,
7540 WINED3DTSS_BUMPENVMAT11 ,
7541 WINED3DTSS_COLORARG0 ,
7542 WINED3DTSS_COLORARG1 ,
7543 WINED3DTSS_COLORARG2 ,
7544 WINED3DTSS_COLOROP ,
7545 WINED3DTSS_RESULTARG ,
7546 WINED3DTSS_TEXCOORDINDEX ,
7547 WINED3DTSS_TEXTURETRANSFORMFLAGS
7550 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7551 WINED3DSAMP_ADDRESSU ,
7552 WINED3DSAMP_ADDRESSV ,
7553 WINED3DSAMP_ADDRESSW ,
7554 WINED3DSAMP_BORDERCOLOR ,
7555 WINED3DSAMP_MAGFILTER ,
7556 WINED3DSAMP_MINFILTER ,
7557 WINED3DSAMP_MIPFILTER ,
7558 WINED3DSAMP_MIPMAPLODBIAS ,
7559 WINED3DSAMP_MAXMIPLEVEL ,
7560 WINED3DSAMP_MAXANISOTROPY ,
7561 WINED3DSAMP_SRGBTEXTURE ,
7562 WINED3DSAMP_ELEMENTINDEX
7565 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7567 WINED3DRS_AMBIENTMATERIALSOURCE ,
7568 WINED3DRS_CLIPPING ,
7569 WINED3DRS_CLIPPLANEENABLE ,
7570 WINED3DRS_COLORVERTEX ,
7571 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7572 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7573 WINED3DRS_FOGDENSITY ,
7575 WINED3DRS_FOGSTART ,
7576 WINED3DRS_FOGTABLEMODE ,
7577 WINED3DRS_FOGVERTEXMODE ,
7578 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7579 WINED3DRS_LIGHTING ,
7580 WINED3DRS_LOCALVIEWER ,
7581 WINED3DRS_MULTISAMPLEANTIALIAS ,
7582 WINED3DRS_MULTISAMPLEMASK ,
7583 WINED3DRS_NORMALIZENORMALS ,
7584 WINED3DRS_PATCHEDGESTYLE ,
7585 WINED3DRS_POINTSCALE_A ,
7586 WINED3DRS_POINTSCALE_B ,
7587 WINED3DRS_POINTSCALE_C ,
7588 WINED3DRS_POINTSCALEENABLE ,
7589 WINED3DRS_POINTSIZE ,
7590 WINED3DRS_POINTSIZE_MAX ,
7591 WINED3DRS_POINTSIZE_MIN ,
7592 WINED3DRS_POINTSPRITEENABLE ,
7593 WINED3DRS_RANGEFOGENABLE ,
7594 WINED3DRS_SPECULARMATERIALSOURCE ,
7595 WINED3DRS_TWEENFACTOR ,
7596 WINED3DRS_VERTEXBLEND ,
7597 WINED3DRS_CULLMODE ,
7601 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7602 WINED3DTSS_TEXCOORDINDEX ,
7603 WINED3DTSS_TEXTURETRANSFORMFLAGS
7606 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7607 WINED3DSAMP_DMAPOFFSET
7610 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7611 DWORD rep = This->StateTable[state].representative;
7612 struct wined3d_context *context;
7617 for(i = 0; i < This->numContexts; i++) {
7618 context = This->contexts[i];
7619 if(isStateDirty(context, rep)) continue;
7621 context->dirtyArray[context->numDirtyEntries++] = rep;
7624 context->isStateDirty[idx] |= (1 << shift);
7628 void get_drawable_size_pbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7630 IWineD3DDeviceImpl *device = ((IWineD3DSurfaceImpl *)context->current_rt)->resource.wineD3DDevice;
7631 /* The drawable size of a pbuffer render target is the current pbuffer size. */
7632 *width = device->pbufferWidth;
7633 *height = device->pbufferHeight;
7636 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7638 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->current_rt;
7639 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7640 *width = surface->pow2Width;
7641 *height = surface->pow2Height;
7644 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7646 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)context->surface;
7647 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7648 * current context's drawable, which is the size of the back buffer of the swapchain
7649 * the active context belongs to. The back buffer of the swapchain is stored as the
7650 * surface the context belongs to. */
7651 *width = surface->currentDesc.Width;
7652 *height = surface->currentDesc.Height;