2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
12 * Copyright 2009 Henri Verbeet for CodeWeavers
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
34 #include "wined3d_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
37 #define GLINFO_LOCATION This->adapter->gl_info
39 /* Define the default light parameters as specified by MSDN */
40 const WINED3DLIGHT WINED3D_default_light = {
42 WINED3DLIGHT_DIRECTIONAL, /* Type */
43 { 1.0f, 1.0f, 1.0f, 0.0f }, /* Diffuse r,g,b,a */
44 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Specular r,g,b,a */
45 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Ambient r,g,b,a, */
46 { 0.0f, 0.0f, 0.0f }, /* Position x,y,z */
47 { 0.0f, 0.0f, 1.0f }, /* Direction x,y,z */
50 0.0f, 0.0f, 0.0f, /* Attenuation 0,1,2 */
55 /**********************************************************
56 * Global variable / Constants follow
57 **********************************************************/
58 const float identity[] =
60 1.0f, 0.0f, 0.0f, 0.0f,
61 0.0f, 1.0f, 0.0f, 0.0f,
62 0.0f, 0.0f, 1.0f, 0.0f,
63 0.0f, 0.0f, 0.0f, 1.0f,
64 }; /* When needed for comparisons */
66 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
67 * actually have the same values in GL and D3D. */
68 static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
70 switch(primitive_type)
72 case WINED3DPT_POINTLIST:
75 case WINED3DPT_LINELIST:
78 case WINED3DPT_LINESTRIP:
81 case WINED3DPT_TRIANGLELIST:
84 case WINED3DPT_TRIANGLESTRIP:
85 return GL_TRIANGLE_STRIP;
87 case WINED3DPT_TRIANGLEFAN:
88 return GL_TRIANGLE_FAN;
90 case WINED3DPT_LINELIST_ADJ:
91 return GL_LINES_ADJACENCY_ARB;
93 case WINED3DPT_LINESTRIP_ADJ:
94 return GL_LINE_STRIP_ADJACENCY_ARB;
96 case WINED3DPT_TRIANGLELIST_ADJ:
97 return GL_TRIANGLES_ADJACENCY_ARB;
99 case WINED3DPT_TRIANGLESTRIP_ADJ:
100 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
103 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
108 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
110 switch(primitive_type)
113 return WINED3DPT_POINTLIST;
116 return WINED3DPT_LINELIST;
119 return WINED3DPT_LINESTRIP;
122 return WINED3DPT_TRIANGLELIST;
124 case GL_TRIANGLE_STRIP:
125 return WINED3DPT_TRIANGLESTRIP;
127 case GL_TRIANGLE_FAN:
128 return WINED3DPT_TRIANGLEFAN;
130 case GL_LINES_ADJACENCY_ARB:
131 return WINED3DPT_LINELIST_ADJ;
133 case GL_LINE_STRIP_ADJACENCY_ARB:
134 return WINED3DPT_LINESTRIP_ADJ;
136 case GL_TRIANGLES_ADJACENCY_ARB:
137 return WINED3DPT_TRIANGLELIST_ADJ;
139 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
140 return WINED3DPT_TRIANGLESTRIP_ADJ;
143 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
144 return WINED3DPT_UNDEFINED;
148 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
150 if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && usage_idx == 0)
151 *regnum = WINED3D_FFP_POSITION;
152 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
153 *regnum = WINED3D_FFP_BLENDWEIGHT;
154 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
155 *regnum = WINED3D_FFP_BLENDINDICES;
156 else if (usage == WINED3DDECLUSAGE_NORMAL && usage_idx == 0)
157 *regnum = WINED3D_FFP_NORMAL;
158 else if (usage == WINED3DDECLUSAGE_PSIZE && usage_idx == 0)
159 *regnum = WINED3D_FFP_PSIZE;
160 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 0)
161 *regnum = WINED3D_FFP_DIFFUSE;
162 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1)
163 *regnum = WINED3D_FFP_SPECULAR;
164 else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
165 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
168 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
176 /* Context activation is done by the caller. */
177 void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
178 BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
180 /* We need to deal with frequency data! */
181 IWineD3DVertexDeclarationImpl *declaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
184 stream_info->use_map = 0;
185 stream_info->swizzle_map = 0;
187 /* Check for transformed vertices, disable vertex shader if present. */
188 stream_info->position_transformed = declaration->position_transformed;
189 if (declaration->position_transformed) use_vshader = FALSE;
191 /* Translate the declaration into strided data. */
192 for (i = 0; i < declaration->element_count; ++i)
194 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
195 GLuint buffer_object = 0;
196 const BYTE *data = NULL;
201 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
202 element, i + 1, declaration->element_count);
204 if (!This->stateBlock->streamSource[element->input_slot]) continue;
206 stride = This->stateBlock->streamStride[element->input_slot];
207 if (This->stateBlock->streamIsUP)
209 TRACE("Stream %u is UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
211 data = (BYTE *)This->stateBlock->streamSource[element->input_slot];
215 TRACE("Stream %u isn't UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
216 data = buffer_get_memory(This->stateBlock->streamSource[element->input_slot], &buffer_object);
218 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
219 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
220 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
221 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
222 * not, drawStridedSlow is needed, including a vertex buffer path. */
223 if (This->stateBlock->loadBaseVertexIndex < 0)
225 WARN("loadBaseVertexIndex is < 0 (%d), not using vbos\n", This->stateBlock->loadBaseVertexIndex);
227 data = buffer_get_sysmem((struct wined3d_buffer *)This->stateBlock->streamSource[element->input_slot]);
228 if ((UINT_PTR)data < -This->stateBlock->loadBaseVertexIndex * stride)
230 FIXME("System memory vertex data load offset is negative!\n");
236 if (buffer_object) *fixup = TRUE;
237 else if (*fixup && !use_vshader
238 && (element->usage == WINED3DDECLUSAGE_COLOR
239 || element->usage == WINED3DDECLUSAGE_POSITIONT))
241 static BOOL warned = FALSE;
244 /* This may be bad with the fixed function pipeline. */
245 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
251 data += element->offset;
253 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
257 if (element->output_slot == ~0U)
259 /* TODO: Assuming vertexdeclarations are usually used with the
260 * same or a similar shader, it might be worth it to store the
261 * last used output slot and try that one first. */
262 stride_used = vshader_get_input(This->stateBlock->vertexShader,
263 element->usage, element->usage_idx, &idx);
267 idx = element->output_slot;
273 if (!element->ffp_valid)
275 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
276 debug_d3dformat(element->format_desc->format), debug_d3ddeclusage(element->usage));
281 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
287 TRACE("Load %s array %u [usage %s, usage_idx %u, "
288 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
289 use_vshader ? "shader": "fixed function", idx,
290 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
291 element->offset, stride, debug_d3dformat(element->format_desc->format), buffer_object);
293 stream_info->elements[idx].format_desc = element->format_desc;
294 stream_info->elements[idx].stride = stride;
295 stream_info->elements[idx].data = data;
296 stream_info->elements[idx].stream_idx = element->input_slot;
297 stream_info->elements[idx].buffer_object = buffer_object;
299 if (!This->adapter->gl_info.supported[ARB_VERTEX_ARRAY_BGRA]
300 && element->format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
302 stream_info->swizzle_map |= 1 << idx;
304 stream_info->use_map |= 1 << idx;
308 This->num_buffer_queries = 0;
309 if (!This->stateBlock->streamIsUP)
311 WORD map = stream_info->use_map;
313 /* PreLoad all the vertex buffers. */
314 for (i = 0; map; map >>= 1, ++i)
316 struct wined3d_stream_info_element *element;
317 struct wined3d_buffer *buffer;
318 struct wined3d_event_query *query;
320 if (!(map & 1)) continue;
322 element = &stream_info->elements[i];
323 buffer = (struct wined3d_buffer *)This->stateBlock->streamSource[element->stream_idx];
324 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)buffer);
326 /* If PreLoad dropped the buffer object, update the stream info. */
327 if (buffer->buffer_object != element->buffer_object)
329 element->buffer_object = 0;
330 element->data = buffer_get_sysmem(buffer) + (ptrdiff_t)element->data;
333 query = ((struct wined3d_buffer *) buffer)->query;
336 This->buffer_queries[This->num_buffer_queries++] = query;
342 static void stream_info_element_from_strided(const struct wined3d_gl_info *gl_info,
343 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
345 const struct wined3d_format_desc *format_desc = getFormatDescEntry(strided->format, gl_info);
346 e->format_desc = format_desc;
347 e->stride = strided->dwStride;
348 e->data = strided->lpData;
350 e->buffer_object = 0;
353 static void device_stream_info_from_strided(const struct wined3d_gl_info *gl_info,
354 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
358 memset(stream_info, 0, sizeof(*stream_info));
360 if (strided->position.lpData)
361 stream_info_element_from_strided(gl_info, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
362 if (strided->normal.lpData)
363 stream_info_element_from_strided(gl_info, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
364 if (strided->diffuse.lpData)
365 stream_info_element_from_strided(gl_info, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
366 if (strided->specular.lpData)
367 stream_info_element_from_strided(gl_info, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
369 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
371 if (strided->texCoords[i].lpData)
372 stream_info_element_from_strided(gl_info, &strided->texCoords[i],
373 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
376 stream_info->position_transformed = strided->position_transformed;
378 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
380 if (!stream_info->elements[i].format_desc) continue;
382 if (!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
383 && stream_info->elements[i].format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
385 stream_info->swizzle_map |= 1 << i;
387 stream_info->use_map |= 1 << i;
391 static void device_trace_strided_stream_info(const struct wined3d_stream_info *stream_info)
393 TRACE("Strided Data:\n");
394 TRACE_STRIDED(stream_info, WINED3D_FFP_POSITION);
395 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDWEIGHT);
396 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDINDICES);
397 TRACE_STRIDED(stream_info, WINED3D_FFP_NORMAL);
398 TRACE_STRIDED(stream_info, WINED3D_FFP_PSIZE);
399 TRACE_STRIDED(stream_info, WINED3D_FFP_DIFFUSE);
400 TRACE_STRIDED(stream_info, WINED3D_FFP_SPECULAR);
401 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD0);
402 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD1);
403 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD2);
404 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD3);
405 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD4);
406 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD5);
407 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD6);
408 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD7);
411 /* Context activation is done by the caller. */
412 void device_update_stream_info(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
414 struct wined3d_stream_info *stream_info = &device->strided_streams;
415 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
416 BOOL vs = stateblock->vertexShader && device->vs_selected_mode != SHADER_NONE;
419 if (device->up_strided)
421 /* Note: this is a ddraw fixed-function code path. */
422 TRACE("=============================== Strided Input ================================\n");
423 device_stream_info_from_strided(gl_info, device->up_strided, stream_info);
424 if (TRACE_ON(d3d)) device_trace_strided_stream_info(stream_info);
428 TRACE("============================= Vertex Declaration =============================\n");
429 device_stream_info_from_declaration(device, vs, stream_info, &fixup);
432 if (vs && !stream_info->position_transformed)
434 if (((IWineD3DVertexDeclarationImpl *)stateblock->vertexDecl)->half_float_conv_needed && !fixup)
436 TRACE("Using drawStridedSlow with vertex shaders for FLOAT16 conversion.\n");
437 device->useDrawStridedSlow = TRUE;
441 device->useDrawStridedSlow = FALSE;
446 WORD slow_mask = (1 << WINED3D_FFP_PSIZE);
447 slow_mask |= -!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
448 & ((1 << WINED3D_FFP_DIFFUSE) | (1 << WINED3D_FFP_SPECULAR));
450 if ((stream_info->position_transformed || (stream_info->use_map & slow_mask)) && !fixup)
452 device->useDrawStridedSlow = TRUE;
456 device->useDrawStridedSlow = FALSE;
461 static void device_preload_texture(IWineD3DStateBlockImpl *stateblock, unsigned int idx)
463 IWineD3DBaseTextureImpl *texture;
464 enum WINED3DSRGB srgb;
466 if (!(texture = (IWineD3DBaseTextureImpl *)stateblock->textures[idx])) return;
467 srgb = stateblock->samplerState[idx][WINED3DSAMP_SRGBTEXTURE] ? SRGB_SRGB : SRGB_RGB;
468 texture->baseTexture.internal_preload((IWineD3DBaseTexture *)texture, srgb);
471 void device_preload_textures(IWineD3DDeviceImpl *device)
473 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
476 if (use_vs(stateblock))
478 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i)
480 if (((IWineD3DBaseShaderImpl *)stateblock->vertexShader)->baseShader.reg_maps.sampler_type[i])
481 device_preload_texture(stateblock, MAX_FRAGMENT_SAMPLERS + i);
485 if (use_ps(stateblock))
487 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
489 if (((IWineD3DBaseShaderImpl *)stateblock->pixelShader)->baseShader.reg_maps.sampler_type[i])
490 device_preload_texture(stateblock, i);
495 WORD ffu_map = device->fixed_function_usage_map;
497 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
500 device_preload_texture(stateblock, i);
505 BOOL device_context_add(IWineD3DDeviceImpl *device, struct wined3d_context *context)
507 struct wined3d_context **new_array;
509 TRACE("Adding context %p.\n", context);
511 if (!device->contexts) new_array = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_array));
512 else new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, sizeof(*new_array) * (device->numContexts + 1));
516 ERR("Failed to grow the context array.\n");
520 new_array[device->numContexts++] = context;
521 device->contexts = new_array;
525 void device_context_remove(IWineD3DDeviceImpl *device, struct wined3d_context *context)
527 struct wined3d_context **new_array;
531 TRACE("Removing context %p.\n", context);
533 for (i = 0; i < device->numContexts; ++i)
535 if (device->contexts[i] == context)
544 ERR("Context %p doesn't exist in context array.\n", context);
548 if (!--device->numContexts)
550 HeapFree(GetProcessHeap(), 0, device->contexts);
551 device->contexts = NULL;
555 memmove(&device->contexts[i], &device->contexts[i + 1], (device->numContexts - i) * sizeof(*device->contexts));
556 new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, device->numContexts * sizeof(*device->contexts));
559 ERR("Failed to shrink context array. Oh well.\n");
563 device->contexts = new_array;
566 void device_get_draw_rect(IWineD3DDeviceImpl *device, RECT *rect)
568 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
569 WINED3DVIEWPORT *vp = &stateblock->viewport;
571 SetRect(rect, vp->X, vp->Y, vp->X + vp->Width, vp->Y + vp->Height);
573 if (stateblock->renderState[WINED3DRS_SCISSORTESTENABLE])
575 IntersectRect(rect, rect, &stateblock->scissorRect);
579 void device_switch_onscreen_ds(IWineD3DDeviceImpl *device,
580 struct wined3d_context *context, IWineD3DSurfaceImpl *depth_stencil)
582 if (device->onscreen_depth_stencil)
584 surface_load_ds_location(device->onscreen_depth_stencil, context, SFLAG_DS_OFFSCREEN);
585 surface_modify_ds_location(device->onscreen_depth_stencil, SFLAG_DS_OFFSCREEN,
586 device->onscreen_depth_stencil->ds_current_size.cx,
587 device->onscreen_depth_stencil->ds_current_size.cy);
588 IWineD3DSurface_Release((IWineD3DSurface *)device->onscreen_depth_stencil);
590 device->onscreen_depth_stencil = depth_stencil;
591 IWineD3DSurface_AddRef((IWineD3DSurface *)device->onscreen_depth_stencil);
594 /**********************************************************
595 * IUnknown parts follows
596 **********************************************************/
598 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
602 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
603 if (IsEqualGUID(riid, &IID_IUnknown)
604 || IsEqualGUID(riid, &IID_IWineD3DBase)
605 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
606 IUnknown_AddRef(iface);
611 return E_NOINTERFACE;
614 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
615 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
616 ULONG refCount = InterlockedIncrement(&This->ref);
618 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
622 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
623 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
624 ULONG refCount = InterlockedDecrement(&This->ref);
626 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
631 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
632 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
633 This->multistate_funcs[i] = NULL;
636 /* TODO: Clean up all the surfaces and textures! */
637 /* NOTE: You must release the parent if the object was created via a callback
638 ** ***************************/
640 if (!list_empty(&This->resources))
642 IWineD3DResourceImpl *resource;
643 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
645 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
647 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
648 FIXME("Leftover resource %p with type %s (%#x).\n",
649 resource, debug_d3dresourcetype(type), type);
653 if(This->contexts) ERR("Context array not freed!\n");
654 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
655 This->haveHardwareCursor = FALSE;
657 IWineD3D_Release(This->wined3d);
658 This->wined3d = NULL;
659 HeapFree(GetProcessHeap(), 0, This);
660 TRACE("Freed device %p\n", This);
666 /**********************************************************
667 * IWineD3DDevice implementation follows
668 **********************************************************/
669 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
670 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
671 *pParent = This->parent;
672 IUnknown_AddRef(This->parent);
676 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
677 const void *data, IUnknown *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
679 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
680 struct wined3d_buffer *object;
683 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
685 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
688 ERR("Failed to allocate memory\n");
689 return E_OUTOFMEMORY;
692 FIXME("Ignoring access flags (pool)\n");
694 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
695 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
698 WARN("Failed to initialize buffer, hr %#x.\n", hr);
699 HeapFree(GetProcessHeap(), 0, object);
702 object->desc = *desc;
704 TRACE("Created buffer %p.\n", object);
706 *buffer = (IWineD3DBuffer *)object;
711 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface,
712 UINT Size, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer,
713 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
715 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
716 struct wined3d_buffer *object;
719 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
720 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
722 if (Pool == WINED3DPOOL_SCRATCH)
724 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
725 * anyway, SCRATCH vertex buffers aren't usable anywhere
727 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
728 *ppVertexBuffer = NULL;
729 return WINED3DERR_INVALIDCALL;
732 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
735 ERR("Out of memory\n");
736 *ppVertexBuffer = NULL;
737 return WINED3DERR_OUTOFVIDEOMEMORY;
740 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
741 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
744 WARN("Failed to initialize buffer, hr %#x.\n", hr);
745 HeapFree(GetProcessHeap(), 0, object);
749 TRACE("Created buffer %p.\n", object);
750 *ppVertexBuffer = (IWineD3DBuffer *)object;
755 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
756 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer,
757 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
759 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
760 struct wined3d_buffer *object;
763 TRACE("(%p) Creating index buffer\n", This);
765 /* Allocate the storage for the device */
766 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
769 ERR("Out of memory\n");
770 *ppIndexBuffer = NULL;
771 return WINED3DERR_OUTOFVIDEOMEMORY;
774 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
775 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
779 WARN("Failed to initialize buffer, hr %#x\n", hr);
780 HeapFree(GetProcessHeap(), 0, object);
784 TRACE("Created buffer %p.\n", object);
786 *ppIndexBuffer = (IWineD3DBuffer *) object;
791 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
792 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock, IUnknown *parent)
794 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
795 IWineD3DStateBlockImpl *object;
798 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
801 ERR("Failed to allocate stateblock memory.\n");
802 return E_OUTOFMEMORY;
805 hr = stateblock_init(object, This, type);
808 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
809 HeapFree(GetProcessHeap(), 0, object);
813 TRACE("Created stateblock %p.\n", object);
814 *stateblock = (IWineD3DStateBlock *)object;
819 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
820 WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,
821 DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
822 WINED3DSURFTYPE Impl, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
824 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
825 IWineD3DSurfaceImpl *object;
828 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
829 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
830 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
831 ppSurface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
832 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
834 if (Impl == SURFACE_OPENGL && !This->adapter)
836 ERR("OpenGL surfaces are not available without OpenGL.\n");
837 return WINED3DERR_NOTAVAILABLE;
840 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
843 ERR("Failed to allocate surface memory.\n");
844 return WINED3DERR_OUTOFVIDEOMEMORY;
847 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
848 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
851 WARN("Failed to initialize surface, returning %#x.\n", hr);
852 HeapFree(GetProcessHeap(), 0, object);
856 TRACE("(%p) : Created surface %p\n", This, object);
858 *ppSurface = (IWineD3DSurface *)object;
863 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
864 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
866 struct wined3d_rendertarget_view *object;
868 TRACE("iface %p, resource %p, parent %p, rendertarget_view %p.\n",
869 iface, resource, parent, rendertarget_view);
871 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
874 ERR("Failed to allocate memory\n");
875 return E_OUTOFMEMORY;
878 wined3d_rendertarget_view_init(object, resource, parent);
880 TRACE("Created render target view %p.\n", object);
881 *rendertarget_view = (IWineD3DRendertargetView *)object;
886 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
887 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
888 IWineD3DTexture **ppTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
890 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
891 IWineD3DTextureImpl *object;
894 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
895 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
896 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
898 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
901 ERR("Out of memory\n");
903 return WINED3DERR_OUTOFVIDEOMEMORY;
906 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
909 WARN("Failed to initialize texture, returning %#x\n", hr);
910 HeapFree(GetProcessHeap(), 0, object);
915 *ppTexture = (IWineD3DTexture *)object;
917 TRACE("(%p) : Created texture %p\n", This, object);
922 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
923 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
924 IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
927 IWineD3DVolumeTextureImpl *object;
930 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
931 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
933 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
936 ERR("Out of memory\n");
937 *ppVolumeTexture = NULL;
938 return WINED3DERR_OUTOFVIDEOMEMORY;
941 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
944 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
945 HeapFree(GetProcessHeap(), 0, object);
946 *ppVolumeTexture = NULL;
950 TRACE("(%p) : Created volume texture %p.\n", This, object);
951 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
956 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
957 UINT Depth, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DVolume **ppVolume,
958 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
960 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
961 IWineD3DVolumeImpl *object;
964 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
965 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
967 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
970 ERR("Out of memory\n");
972 return WINED3DERR_OUTOFVIDEOMEMORY;
975 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
978 WARN("Failed to initialize volume, returning %#x.\n", hr);
979 HeapFree(GetProcessHeap(), 0, object);
983 TRACE("(%p) : Created volume %p.\n", This, object);
984 *ppVolume = (IWineD3DVolume *)object;
989 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
990 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture,
991 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
993 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
994 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
997 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1000 ERR("Out of memory\n");
1001 *ppCubeTexture = NULL;
1002 return WINED3DERR_OUTOFVIDEOMEMORY;
1005 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
1008 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1009 HeapFree(GetProcessHeap(), 0, object);
1010 *ppCubeTexture = NULL;
1014 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1015 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1020 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
1021 WINED3DQUERYTYPE type, IWineD3DQuery **query, IUnknown *parent)
1023 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1024 IWineD3DQueryImpl *object;
1027 TRACE("iface %p, type %#x, query %p, parent %p.\n", iface, type, query, parent);
1029 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1032 ERR("Failed to allocate query memory.\n");
1033 return E_OUTOFMEMORY;
1036 hr = query_init(object, This, type, parent);
1039 WARN("Failed to initialize query, hr %#x.\n", hr);
1040 HeapFree(GetProcessHeap(), 0, object);
1044 TRACE("Created query %p.\n", object);
1045 *query = (IWineD3DQuery *)object;
1050 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1051 WINED3DPRESENT_PARAMETERS *present_parameters, IWineD3DSwapChain **swapchain,
1052 IUnknown *parent, WINED3DSURFTYPE surface_type)
1054 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1055 IWineD3DSwapChainImpl *object;
1058 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1059 iface, present_parameters, swapchain, parent, surface_type);
1061 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1064 ERR("Failed to allocate swapchain memory.\n");
1065 return E_OUTOFMEMORY;
1068 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
1071 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1072 HeapFree(GetProcessHeap(), 0, object);
1076 TRACE("Created swapchain %p.\n", object);
1077 *swapchain = (IWineD3DSwapChain *)object;
1082 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1083 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1084 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1085 TRACE("(%p)\n", This);
1087 return This->NumberOfSwapChains;
1090 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1091 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1092 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1094 if(iSwapChain < This->NumberOfSwapChains) {
1095 *pSwapChain = This->swapchains[iSwapChain];
1096 IWineD3DSwapChain_AddRef(*pSwapChain);
1097 TRACE("(%p) returning %p\n", This, *pSwapChain);
1100 TRACE("Swapchain out of range\n");
1102 return WINED3DERR_INVALIDCALL;
1106 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1107 IWineD3DVertexDeclaration **declaration, IUnknown *parent, const struct wined3d_parent_ops *parent_ops,
1108 const WINED3DVERTEXELEMENT *elements, UINT element_count)
1110 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1111 IWineD3DVertexDeclarationImpl *object = NULL;
1114 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1115 iface, declaration, parent, elements, element_count);
1117 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1120 ERR("Failed to allocate vertex declaration memory.\n");
1121 return E_OUTOFMEMORY;
1124 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1127 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1128 HeapFree(GetProcessHeap(), 0, object);
1132 TRACE("Created vertex declaration %p.\n", object);
1133 *declaration = (IWineD3DVertexDeclaration *)object;
1138 struct wined3d_fvf_convert_state
1140 const struct wined3d_gl_info *gl_info;
1141 WINED3DVERTEXELEMENT *elements;
1146 static void append_decl_element(struct wined3d_fvf_convert_state *state,
1147 WINED3DFORMAT format, WINED3DDECLUSAGE usage, UINT usage_idx)
1149 WINED3DVERTEXELEMENT *elements = state->elements;
1150 const struct wined3d_format_desc *format_desc;
1151 UINT offset = state->offset;
1152 UINT idx = state->idx;
1154 elements[idx].format = format;
1155 elements[idx].input_slot = 0;
1156 elements[idx].offset = offset;
1157 elements[idx].output_slot = 0;
1158 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1159 elements[idx].usage = usage;
1160 elements[idx].usage_idx = usage_idx;
1162 format_desc = getFormatDescEntry(format, state->gl_info);
1163 state->offset += format_desc->component_count * format_desc->component_size;
1167 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1168 DWORD fvf, WINED3DVERTEXELEMENT **ppVertexElements)
1170 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1171 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1172 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1173 BOOL has_blend_idx = has_blend &&
1174 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1175 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1176 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1177 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1178 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1179 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1180 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1182 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1183 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1184 struct wined3d_fvf_convert_state state;
1187 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1188 if (has_blend_idx) num_blends--;
1190 /* Compute declaration size */
1191 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1192 has_psize + has_diffuse + has_specular + num_textures;
1194 state.gl_info = gl_info;
1195 state.elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*state.elements));
1196 if (!state.elements) return ~0U;
1202 if (!has_blend && (fvf & WINED3DFVF_XYZRHW))
1203 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITIONT, 0);
1204 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW)
1205 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1207 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1210 if (has_blend && (num_blends > 0))
1212 if ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1213 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1219 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1222 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1225 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1228 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1231 ERR("Unexpected amount of blend values: %u\n", num_blends);
1238 if ((fvf & WINED3DFVF_LASTBETA_UBYTE4)
1239 || ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1240 append_decl_element(&state, WINED3DFMT_R8G8B8A8_UINT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1241 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1242 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDINDICES, 0);
1244 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1247 if (has_normal) append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_NORMAL, 0);
1248 if (has_psize) append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_PSIZE, 0);
1249 if (has_diffuse) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 0);
1250 if (has_specular) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 1);
1252 for (idx = 0; idx < num_textures; ++idx)
1254 switch ((texcoords >> (idx * 2)) & 0x03)
1256 case WINED3DFVF_TEXTUREFORMAT1:
1257 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1259 case WINED3DFVF_TEXTUREFORMAT2:
1260 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1262 case WINED3DFVF_TEXTUREFORMAT3:
1263 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1265 case WINED3DFVF_TEXTUREFORMAT4:
1266 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1271 *ppVertexElements = state.elements;
1275 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1276 IWineD3DVertexDeclaration **declaration, IUnknown *parent,
1277 const struct wined3d_parent_ops *parent_ops, DWORD fvf)
1279 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1280 WINED3DVERTEXELEMENT *elements;
1284 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1286 size = ConvertFvfToDeclaration(This, fvf, &elements);
1287 if (size == ~0U) return E_OUTOFMEMORY;
1289 hr = IWineD3DDevice_CreateVertexDeclaration(iface, declaration, parent, parent_ops, elements, size);
1290 HeapFree(GetProcessHeap(), 0, elements);
1294 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1295 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1296 IWineD3DVertexShader **ppVertexShader, IUnknown *parent,
1297 const struct wined3d_parent_ops *parent_ops)
1299 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1300 IWineD3DVertexShaderImpl *object;
1303 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1306 ERR("Failed to allocate shader memory.\n");
1307 return E_OUTOFMEMORY;
1310 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1313 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1314 HeapFree(GetProcessHeap(), 0, object);
1318 TRACE("Created vertex shader %p.\n", object);
1319 *ppVertexShader = (IWineD3DVertexShader *)object;
1324 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1325 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1326 IWineD3DGeometryShader **shader, IUnknown *parent,
1327 const struct wined3d_parent_ops *parent_ops)
1329 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1330 struct wined3d_geometryshader *object;
1333 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1336 ERR("Failed to allocate shader memory.\n");
1337 return E_OUTOFMEMORY;
1340 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1343 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1344 HeapFree(GetProcessHeap(), 0, object);
1348 TRACE("Created geometry shader %p.\n", object);
1349 *shader = (IWineD3DGeometryShader *)object;
1354 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1355 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1356 IWineD3DPixelShader **ppPixelShader, IUnknown *parent,
1357 const struct wined3d_parent_ops *parent_ops)
1359 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1360 IWineD3DPixelShaderImpl *object;
1363 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1366 ERR("Failed to allocate shader memory.\n");
1367 return E_OUTOFMEMORY;
1370 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1373 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1374 HeapFree(GetProcessHeap(), 0, object);
1378 TRACE("Created pixel shader %p.\n", object);
1379 *ppPixelShader = (IWineD3DPixelShader *)object;
1384 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1385 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1387 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1388 IWineD3DPaletteImpl *object;
1391 TRACE("iface %p, flags %#x, entries %p, palette %p, parent %p.\n",
1392 iface, Flags, PalEnt, Palette, Parent);
1394 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1397 ERR("Failed to allocate palette memory.\n");
1398 return E_OUTOFMEMORY;
1401 hr = wined3d_palette_init(object, This, Flags, PalEnt, Parent);
1404 WARN("Failed to initialize palette, hr %#x.\n", hr);
1405 HeapFree(GetProcessHeap(), 0, object);
1409 TRACE("Created palette %p.\n", object);
1410 *Palette = (IWineD3DPalette *)object;
1415 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1419 HDC dcb = NULL, dcs = NULL;
1420 WINEDDCOLORKEY colorkey;
1422 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1425 GetObjectA(hbm, sizeof(BITMAP), &bm);
1426 dcb = CreateCompatibleDC(NULL);
1428 SelectObject(dcb, hbm);
1432 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1433 * couldn't be loaded
1435 memset(&bm, 0, sizeof(bm));
1440 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1441 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1442 NULL, &wined3d_null_parent_ops);
1444 ERR("Wine logo requested, but failed to create surface\n");
1449 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1450 if(FAILED(hr)) goto out;
1451 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1452 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1454 colorkey.dwColorSpaceLowValue = 0;
1455 colorkey.dwColorSpaceHighValue = 0;
1456 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1458 /* Fill the surface with a white color to show that wined3d is there */
1459 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1463 if (dcb) DeleteDC(dcb);
1464 if (hbm) DeleteObject(hbm);
1467 /* Context activation is done by the caller. */
1468 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1470 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1472 /* Under DirectX you can have texture stage operations even if no texture is
1473 bound, whereas opengl will only do texture operations when a valid texture is
1474 bound. We emulate this by creating dummy textures and binding them to each
1475 texture stage, but disable all stages by default. Hence if a stage is enabled
1476 then the default texture will kick in until replaced by a SetTexture call */
1479 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1481 /* The dummy texture does not have client storage backing */
1482 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1483 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1486 for (i = 0; i < gl_info->limits.textures; ++i)
1488 GLubyte white = 255;
1490 /* Make appropriate texture active */
1491 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1492 checkGLcall("glActiveTextureARB");
1494 /* Generate an opengl texture name */
1495 glGenTextures(1, &This->dummyTextureName[i]);
1496 checkGLcall("glGenTextures");
1497 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1499 /* Generate a dummy 2d texture (not using 1d because they cause many
1500 * DRI drivers fall back to sw) */
1501 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1502 checkGLcall("glBindTexture");
1504 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1505 checkGLcall("glTexImage2D");
1508 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1510 /* Reenable because if supported it is enabled by default */
1511 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1512 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1518 /* Context activation is done by the caller. */
1519 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1522 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1523 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1526 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1529 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1531 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1533 if (!wined3d_register_window(window, device))
1535 ERR("Failed to register window %p.\n", window);
1539 device->focus_window = window;
1540 SetForegroundWindow(window);
1545 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1547 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1549 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1550 device->focus_window = NULL;
1553 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1554 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1556 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1557 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1558 IWineD3DSwapChainImpl *swapchain = NULL;
1559 struct wined3d_context *context;
1564 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1566 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1567 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1569 TRACE("(%p) : Creating stateblock\n", This);
1570 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1571 hr = IWineD3DDevice_CreateStateBlock(iface,
1573 (IWineD3DStateBlock **)&This->stateBlock,
1575 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1576 WARN("Failed to create stateblock\n");
1579 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1580 This->updateStateBlock = This->stateBlock;
1581 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1583 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1584 sizeof(*This->render_targets) * gl_info->limits.buffers);
1585 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1586 sizeof(GLenum) * gl_info->limits.buffers);
1588 This->NumberOfPalettes = 1;
1589 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1590 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
1591 ERR("Out of memory!\n");
1595 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1596 if(!This->palettes[0]) {
1597 ERR("Out of memory!\n");
1601 for (i = 0; i < 256; ++i) {
1602 This->palettes[0][i].peRed = 0xFF;
1603 This->palettes[0][i].peGreen = 0xFF;
1604 This->palettes[0][i].peBlue = 0xFF;
1605 This->palettes[0][i].peFlags = 0xFF;
1607 This->currentPalette = 0;
1609 /* Initialize the texture unit mapping to a 1:1 mapping */
1610 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1612 if (state < gl_info->limits.fragment_samplers)
1614 This->texUnitMap[state] = state;
1615 This->rev_tex_unit_map[state] = state;
1617 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1618 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1622 /* Setup the implicit swapchain. This also initializes a context. */
1623 TRACE("Creating implicit swapchain\n");
1624 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1625 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1628 WARN("Failed to create implicit swapchain\n");
1632 This->NumberOfSwapChains = 1;
1633 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1634 if(!This->swapchains) {
1635 ERR("Out of memory!\n");
1638 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1640 if (swapchain->back_buffers && swapchain->back_buffers[0])
1642 TRACE("Setting rendertarget to %p.\n", swapchain->back_buffers);
1643 This->render_targets[0] = swapchain->back_buffers[0];
1647 TRACE("Setting rendertarget to %p.\n", swapchain->front_buffer);
1648 This->render_targets[0] = swapchain->front_buffer;
1650 IWineD3DSurface_AddRef((IWineD3DSurface *)This->render_targets[0]);
1652 /* Depth Stencil support */
1653 This->depth_stencil = This->auto_depth_stencil;
1654 if (This->depth_stencil)
1655 IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
1657 hr = This->shader_backend->shader_alloc_private(iface);
1659 TRACE("Shader private data couldn't be allocated\n");
1662 hr = This->frag_pipe->alloc_private(iface);
1664 TRACE("Fragment pipeline private data couldn't be allocated\n");
1667 hr = This->blitter->alloc_private(iface);
1669 TRACE("Blitter private data couldn't be allocated\n");
1673 /* Set up some starting GL setup */
1675 /* Setup all the devices defaults */
1676 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1678 context = context_acquire(This, swapchain->front_buffer, CTXUSAGE_RESOURCELOAD);
1680 create_dummy_textures(This);
1684 /* Initialize the current view state */
1685 This->view_ident = 1;
1686 This->contexts[0]->last_was_rhw = 0;
1687 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1688 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1690 switch(wined3d_settings.offscreen_rendering_mode) {
1692 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1695 case ORM_BACKBUFFER:
1697 if (context_get_current()->aux_buffers > 0)
1699 TRACE("Using auxilliary buffer for offscreen rendering\n");
1700 This->offscreenBuffer = GL_AUX0;
1702 TRACE("Using back buffer for offscreen rendering\n");
1703 This->offscreenBuffer = GL_BACK;
1708 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1711 context_release(context);
1713 /* Clear the screen */
1714 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1715 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1718 This->d3d_initialized = TRUE;
1720 if(wined3d_settings.logo) {
1721 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1723 This->highest_dirty_ps_const = 0;
1724 This->highest_dirty_vs_const = 0;
1728 HeapFree(GetProcessHeap(), 0, This->render_targets);
1729 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1730 HeapFree(GetProcessHeap(), 0, This->swapchains);
1731 This->NumberOfSwapChains = 0;
1732 if(This->palettes) {
1733 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1734 HeapFree(GetProcessHeap(), 0, This->palettes);
1736 This->NumberOfPalettes = 0;
1738 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1740 if(This->stateBlock) {
1741 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1742 This->stateBlock = NULL;
1744 if (This->blit_priv) {
1745 This->blitter->free_private(iface);
1747 if (This->fragment_priv) {
1748 This->frag_pipe->free_private(iface);
1750 if (This->shader_priv) {
1751 This->shader_backend->shader_free_private(iface);
1756 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1757 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1759 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1760 IWineD3DSwapChainImpl *swapchain = NULL;
1763 /* Setup the implicit swapchain */
1764 TRACE("Creating implicit swapchain\n");
1765 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1766 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1769 WARN("Failed to create implicit swapchain\n");
1773 This->NumberOfSwapChains = 1;
1774 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1775 if(!This->swapchains) {
1776 ERR("Out of memory!\n");
1779 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1783 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1787 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
1789 IWineD3DResource_UnLoad(resource);
1790 IWineD3DResource_Release(resource);
1794 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
1795 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
1797 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1798 const struct wined3d_gl_info *gl_info;
1799 struct wined3d_context *context;
1802 TRACE("(%p)\n", This);
1804 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1806 /* I don't think that the interface guarantees that the device is destroyed from the same thread
1807 * it was created. Thus make sure a context is active for the glDelete* calls
1809 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
1810 gl_info = context->gl_info;
1812 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
1814 /* Unload resources */
1815 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
1817 TRACE("Deleting high order patches\n");
1818 for(i = 0; i < PATCHMAP_SIZE; i++) {
1819 struct list *e1, *e2;
1820 struct WineD3DRectPatch *patch;
1821 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1822 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1823 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1827 /* Delete the mouse cursor texture */
1828 if(This->cursorTexture) {
1830 glDeleteTextures(1, &This->cursorTexture);
1832 This->cursorTexture = 0;
1835 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
1836 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1838 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
1839 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
1842 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
1843 * private data, it might contain opengl pointers
1845 if(This->depth_blt_texture) {
1847 glDeleteTextures(1, &This->depth_blt_texture);
1849 This->depth_blt_texture = 0;
1851 if (This->depth_blt_rb) {
1853 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
1855 This->depth_blt_rb = 0;
1856 This->depth_blt_rb_w = 0;
1857 This->depth_blt_rb_h = 0;
1860 /* Release the update stateblock */
1861 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
1862 if(This->updateStateBlock != This->stateBlock)
1863 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1865 This->updateStateBlock = NULL;
1867 { /* because were not doing proper internal refcounts releasing the primary state block
1868 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1869 to set this->stateBlock = NULL; first */
1870 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
1871 This->stateBlock = NULL;
1873 /* Release the stateblock */
1874 if(IWineD3DStateBlock_Release(stateBlock) > 0){
1875 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1879 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
1880 This->blitter->free_private(iface);
1881 This->frag_pipe->free_private(iface);
1882 This->shader_backend->shader_free_private(iface);
1884 /* Release the buffers (with sanity checks)*/
1885 if (This->onscreen_depth_stencil)
1887 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
1888 This->onscreen_depth_stencil = NULL;
1891 TRACE("Releasing the depth stencil buffer at %p\n", This->depth_stencil);
1892 if (This->depth_stencil && IWineD3DSurface_Release((IWineD3DSurface *)This->depth_stencil))
1894 if (This->auto_depth_stencil != This->depth_stencil)
1895 FIXME("(%p) Something is still holding the depth/stencil buffer.\n",This);
1897 This->depth_stencil = NULL;
1899 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1900 IWineD3DSurface_Release((IWineD3DSurface *)This->render_targets[0]);
1902 TRACE("Setting rendertarget to NULL\n");
1903 This->render_targets[0] = NULL;
1905 if (This->auto_depth_stencil)
1907 if (IWineD3DSurface_Release((IWineD3DSurface *)This->auto_depth_stencil))
1909 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
1911 This->auto_depth_stencil = NULL;
1914 context_release(context);
1916 for(i=0; i < This->NumberOfSwapChains; i++) {
1917 TRACE("Releasing the implicit swapchain %d\n", i);
1918 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1919 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1923 HeapFree(GetProcessHeap(), 0, This->swapchains);
1924 This->swapchains = NULL;
1925 This->NumberOfSwapChains = 0;
1927 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
1928 HeapFree(GetProcessHeap(), 0, This->palettes);
1929 This->palettes = NULL;
1930 This->NumberOfPalettes = 0;
1932 HeapFree(GetProcessHeap(), 0, This->render_targets);
1933 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1934 This->render_targets = NULL;
1935 This->draw_buffers = NULL;
1937 This->d3d_initialized = FALSE;
1942 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1943 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1946 for(i=0; i < This->NumberOfSwapChains; i++) {
1947 TRACE("Releasing the implicit swapchain %d\n", i);
1948 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1949 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1953 HeapFree(GetProcessHeap(), 0, This->swapchains);
1954 This->swapchains = NULL;
1955 This->NumberOfSwapChains = 0;
1959 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
1960 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
1961 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
1963 * There is no way to deactivate thread safety once it is enabled.
1965 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
1966 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1968 /*For now just store the flag(needed in case of ddraw) */
1969 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
1972 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
1973 const WINED3DDISPLAYMODE* pMode) {
1975 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1976 const struct wined3d_format_desc *format_desc = getFormatDescEntry(pMode->Format, &This->adapter->gl_info);
1980 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1982 /* Resize the screen even without a window:
1983 * The app could have unset it with SetCooperativeLevel, but not called
1984 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1985 * but we don't have any hwnd
1988 memset(&devmode, 0, sizeof(devmode));
1989 devmode.dmSize = sizeof(devmode);
1990 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1991 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1992 devmode.dmPelsWidth = pMode->Width;
1993 devmode.dmPelsHeight = pMode->Height;
1995 devmode.dmDisplayFrequency = pMode->RefreshRate;
1996 if (pMode->RefreshRate != 0) {
1997 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2000 /* Only change the mode if necessary */
2001 if( (This->ddraw_width == pMode->Width) &&
2002 (This->ddraw_height == pMode->Height) &&
2003 (This->ddraw_format == pMode->Format) &&
2004 (pMode->RefreshRate == 0) ) {
2008 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2009 if (ret != DISP_CHANGE_SUCCESSFUL) {
2010 if(devmode.dmDisplayFrequency != 0) {
2011 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2012 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2013 devmode.dmDisplayFrequency = 0;
2014 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2016 if(ret != DISP_CHANGE_SUCCESSFUL) {
2017 return WINED3DERR_NOTAVAILABLE;
2021 /* Store the new values */
2022 This->ddraw_width = pMode->Width;
2023 This->ddraw_height = pMode->Height;
2024 This->ddraw_format = pMode->Format;
2026 /* And finally clip mouse to our screen */
2027 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2028 ClipCursor(&clip_rc);
2033 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2034 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2035 *ppD3D = This->wined3d;
2036 TRACE("Returning %p.\n", *ppD3D);
2037 IWineD3D_AddRef(*ppD3D);
2041 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2042 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2044 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2045 (This->adapter->TextureRam/(1024*1024)),
2046 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2047 /* return simulated texture memory left */
2048 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2052 * Get / Set Stream Source
2054 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2055 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2057 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2058 IWineD3DBuffer *oldSrc;
2060 if (StreamNumber >= MAX_STREAMS) {
2061 WARN("Stream out of range %d\n", StreamNumber);
2062 return WINED3DERR_INVALIDCALL;
2063 } else if(OffsetInBytes & 0x3) {
2064 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2065 return WINED3DERR_INVALIDCALL;
2068 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2069 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2071 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2073 if(oldSrc == pStreamData &&
2074 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2075 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2076 TRACE("Application is setting the old values over, nothing to do\n");
2080 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2082 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2083 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2086 /* Handle recording of state blocks */
2087 if (This->isRecordingState) {
2088 TRACE("Recording... not performing anything\n");
2089 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2090 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2094 if (pStreamData != NULL) {
2095 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2096 IWineD3DBuffer_AddRef(pStreamData);
2098 if (oldSrc != NULL) {
2099 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2100 IWineD3DBuffer_Release(oldSrc);
2103 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2108 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2109 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2111 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2113 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2114 This->stateBlock->streamSource[StreamNumber],
2115 This->stateBlock->streamOffset[StreamNumber],
2116 This->stateBlock->streamStride[StreamNumber]);
2118 if (StreamNumber >= MAX_STREAMS) {
2119 WARN("Stream out of range %d\n", StreamNumber);
2120 return WINED3DERR_INVALIDCALL;
2122 *pStream = This->stateBlock->streamSource[StreamNumber];
2123 *pStride = This->stateBlock->streamStride[StreamNumber];
2125 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2128 if (*pStream != NULL) {
2129 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2134 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2135 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2136 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2137 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2139 /* Verify input at least in d3d9 this is invalid*/
2140 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2141 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2142 return WINED3DERR_INVALIDCALL;
2144 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2145 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2146 return WINED3DERR_INVALIDCALL;
2149 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2150 return WINED3DERR_INVALIDCALL;
2153 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2154 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2156 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2157 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2159 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2160 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2161 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2167 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2168 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2170 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2171 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2173 TRACE("(%p) : returning %d\n", This, *Divider);
2179 * Get / Set & Multiply Transform
2181 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2182 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2184 /* Most of this routine, comments included copied from ddraw tree initially: */
2185 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2187 /* Handle recording of state blocks */
2188 if (This->isRecordingState) {
2189 TRACE("Recording... not performing anything\n");
2190 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2191 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2196 * If the new matrix is the same as the current one,
2197 * we cut off any further processing. this seems to be a reasonable
2198 * optimization because as was noticed, some apps (warcraft3 for example)
2199 * tend towards setting the same matrix repeatedly for some reason.
2201 * From here on we assume that the new matrix is different, wherever it matters.
2203 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2204 TRACE("The app is setting the same matrix over again\n");
2207 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2211 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2212 where ViewMat = Camera space, WorldMat = world space.
2214 In OpenGL, camera and world space is combined into GL_MODELVIEW
2215 matrix. The Projection matrix stay projection matrix.
2218 /* Capture the times we can just ignore the change for now */
2219 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2220 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2221 /* Handled by the state manager */
2224 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2228 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2229 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2230 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2231 *pMatrix = This->stateBlock->transforms[State];
2235 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2236 const WINED3DMATRIX *mat = NULL;
2239 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2240 * below means it will be recorded in a state block change, but it
2241 * works regardless where it is recorded.
2242 * If this is found to be wrong, change to StateBlock.
2244 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2245 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2247 if (State <= HIGHEST_TRANSFORMSTATE)
2249 mat = &This->updateStateBlock->transforms[State];
2251 FIXME("Unhandled transform state!!\n");
2254 multiply_matrix(&temp, mat, pMatrix);
2256 /* Apply change via set transform - will reapply to eg. lights this way */
2257 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2263 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2264 you can reference any indexes you want as long as that number max are enabled at any
2265 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2266 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2267 but when recording, just build a chain pretty much of commands to be replayed. */
2269 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2271 struct wined3d_light_info *object = NULL;
2272 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2275 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2276 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2278 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2282 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2283 return WINED3DERR_INVALIDCALL;
2286 switch(pLight->Type) {
2287 case WINED3DLIGHT_POINT:
2288 case WINED3DLIGHT_SPOT:
2289 case WINED3DLIGHT_PARALLELPOINT:
2290 case WINED3DLIGHT_GLSPOT:
2291 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2294 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2296 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2297 return WINED3DERR_INVALIDCALL;
2301 case WINED3DLIGHT_DIRECTIONAL:
2302 /* Ignores attenuation */
2306 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2307 return WINED3DERR_INVALIDCALL;
2310 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2312 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2313 if(object->OriginalIndex == Index) break;
2318 TRACE("Adding new light\n");
2319 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2321 ERR("Out of memory error when allocating a light\n");
2322 return E_OUTOFMEMORY;
2324 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2325 object->glIndex = -1;
2326 object->OriginalIndex = Index;
2329 /* Initialize the object */
2330 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,
2331 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2332 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2333 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2334 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2335 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2336 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2338 /* Save away the information */
2339 object->OriginalParms = *pLight;
2341 switch (pLight->Type) {
2342 case WINED3DLIGHT_POINT:
2344 object->lightPosn[0] = pLight->Position.x;
2345 object->lightPosn[1] = pLight->Position.y;
2346 object->lightPosn[2] = pLight->Position.z;
2347 object->lightPosn[3] = 1.0f;
2348 object->cutoff = 180.0f;
2352 case WINED3DLIGHT_DIRECTIONAL:
2354 object->lightPosn[0] = -pLight->Direction.x;
2355 object->lightPosn[1] = -pLight->Direction.y;
2356 object->lightPosn[2] = -pLight->Direction.z;
2357 object->lightPosn[3] = 0.0f;
2358 object->exponent = 0.0f;
2359 object->cutoff = 180.0f;
2362 case WINED3DLIGHT_SPOT:
2364 object->lightPosn[0] = pLight->Position.x;
2365 object->lightPosn[1] = pLight->Position.y;
2366 object->lightPosn[2] = pLight->Position.z;
2367 object->lightPosn[3] = 1.0f;
2370 object->lightDirn[0] = pLight->Direction.x;
2371 object->lightDirn[1] = pLight->Direction.y;
2372 object->lightDirn[2] = pLight->Direction.z;
2373 object->lightDirn[3] = 1.0f;
2376 * opengl-ish and d3d-ish spot lights use too different models for the
2377 * light "intensity" as a function of the angle towards the main light direction,
2378 * so we only can approximate very roughly.
2379 * however spot lights are rather rarely used in games (if ever used at all).
2380 * furthermore if still used, probably nobody pays attention to such details.
2382 if (pLight->Falloff == 0) {
2383 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2384 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2385 * will always be 1.0 for both of them, and we don't have to care for the
2386 * rest of the rather complex calculation
2388 object->exponent = 0.0f;
2390 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2391 if (rho < 0.0001f) rho = 0.0001f;
2392 object->exponent = -0.3f/logf(cosf(rho/2));
2394 if (object->exponent > 128.0f)
2396 object->exponent = 128.0f;
2398 object->cutoff = pLight->Phi*90/M_PI;
2404 FIXME("Unrecognized light type %d\n", pLight->Type);
2407 /* Update the live definitions if the light is currently assigned a glIndex */
2408 if (object->glIndex != -1 && !This->isRecordingState) {
2409 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2414 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2416 struct wined3d_light_info *lightInfo = NULL;
2417 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2418 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2420 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2422 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2424 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2425 if(lightInfo->OriginalIndex == Index) break;
2429 if (lightInfo == NULL) {
2430 TRACE("Light information requested but light not defined\n");
2431 return WINED3DERR_INVALIDCALL;
2434 *pLight = lightInfo->OriginalParms;
2439 * Get / Set Light Enable
2440 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2442 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2444 struct wined3d_light_info *lightInfo = NULL;
2445 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2446 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2448 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2450 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2452 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2453 if(lightInfo->OriginalIndex == Index) break;
2456 TRACE("Found light: %p\n", lightInfo);
2458 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2459 if (lightInfo == NULL) {
2461 TRACE("Light enabled requested but light not defined, so defining one!\n");
2462 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2464 /* Search for it again! Should be fairly quick as near head of list */
2465 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2467 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2468 if(lightInfo->OriginalIndex == Index) break;
2471 if (lightInfo == NULL) {
2472 FIXME("Adding default lights has failed dismally\n");
2473 return WINED3DERR_INVALIDCALL;
2478 if(lightInfo->glIndex != -1) {
2479 if(!This->isRecordingState) {
2480 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2483 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2484 lightInfo->glIndex = -1;
2486 TRACE("Light already disabled, nothing to do\n");
2488 lightInfo->enabled = FALSE;
2490 lightInfo->enabled = TRUE;
2491 if (lightInfo->glIndex != -1) {
2493 TRACE("Nothing to do as light was enabled\n");
2496 /* Find a free gl light */
2497 for(i = 0; i < This->maxConcurrentLights; i++) {
2498 if(This->updateStateBlock->activeLights[i] == NULL) {
2499 This->updateStateBlock->activeLights[i] = lightInfo;
2500 lightInfo->glIndex = i;
2504 if(lightInfo->glIndex == -1) {
2505 /* Our tests show that Windows returns D3D_OK in this situation, even with
2506 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2507 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2508 * as well for those lights.
2510 * TODO: Test how this affects rendering
2512 WARN("Too many concurrently active lights\n");
2516 /* i == lightInfo->glIndex */
2517 if(!This->isRecordingState) {
2518 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2526 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2528 struct wined3d_light_info *lightInfo = NULL;
2529 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2531 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2532 TRACE("(%p) : for idx(%d)\n", This, Index);
2534 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2536 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2537 if(lightInfo->OriginalIndex == Index) break;
2541 if (lightInfo == NULL) {
2542 TRACE("Light enabled state requested but light not defined\n");
2543 return WINED3DERR_INVALIDCALL;
2545 /* true is 128 according to SetLightEnable */
2546 *pEnable = lightInfo->enabled ? 128 : 0;
2551 * Get / Set Clip Planes
2553 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2554 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2555 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2557 /* Validate Index */
2558 if (Index >= This->adapter->gl_info.limits.clipplanes)
2560 TRACE("Application has requested clipplane this device doesn't support\n");
2561 return WINED3DERR_INVALIDCALL;
2564 This->updateStateBlock->changed.clipplane |= 1 << Index;
2566 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2567 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2568 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2569 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2570 TRACE("Application is setting old values over, nothing to do\n");
2574 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2575 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2576 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2577 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2579 /* Handle recording of state blocks */
2580 if (This->isRecordingState) {
2581 TRACE("Recording... not performing anything\n");
2585 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2590 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2591 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2592 TRACE("(%p) : for idx %d\n", This, Index);
2594 /* Validate Index */
2595 if (Index >= This->adapter->gl_info.limits.clipplanes)
2597 TRACE("Application has requested clipplane this device doesn't support\n");
2598 return WINED3DERR_INVALIDCALL;
2601 pPlane[0] = This->stateBlock->clipplane[Index][0];
2602 pPlane[1] = This->stateBlock->clipplane[Index][1];
2603 pPlane[2] = This->stateBlock->clipplane[Index][2];
2604 pPlane[3] = This->stateBlock->clipplane[Index][3];
2609 * Get / Set Clip Plane Status
2610 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2612 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2613 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2614 FIXME("(%p) : stub\n", This);
2615 if (NULL == pClipStatus) {
2616 return WINED3DERR_INVALIDCALL;
2618 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2619 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2623 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2625 FIXME("(%p) : stub\n", This);
2626 if (NULL == pClipStatus) {
2627 return WINED3DERR_INVALIDCALL;
2629 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2630 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2635 * Get / Set Material
2637 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2638 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2640 This->updateStateBlock->changed.material = TRUE;
2641 This->updateStateBlock->material = *pMaterial;
2643 /* Handle recording of state blocks */
2644 if (This->isRecordingState) {
2645 TRACE("Recording... not performing anything\n");
2649 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2653 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2655 *pMaterial = This->updateStateBlock->material;
2656 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2657 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2658 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2659 pMaterial->Ambient.b, pMaterial->Ambient.a);
2660 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2661 pMaterial->Specular.b, pMaterial->Specular.a);
2662 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2663 pMaterial->Emissive.b, pMaterial->Emissive.a);
2664 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2672 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2673 IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
2675 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2676 IWineD3DBuffer *oldIdxs;
2678 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2679 oldIdxs = This->updateStateBlock->pIndexData;
2681 This->updateStateBlock->changed.indices = TRUE;
2682 This->updateStateBlock->pIndexData = pIndexData;
2683 This->updateStateBlock->IndexFmt = fmt;
2685 /* Handle recording of state blocks */
2686 if (This->isRecordingState) {
2687 TRACE("Recording... not performing anything\n");
2688 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2689 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2693 if(oldIdxs != pIndexData) {
2694 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2696 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2697 IWineD3DBuffer_AddRef(pIndexData);
2700 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2701 IWineD3DBuffer_Release(oldIdxs);
2708 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2710 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2712 *ppIndexData = This->stateBlock->pIndexData;
2714 /* up ref count on ppindexdata */
2716 IWineD3DBuffer_AddRef(*ppIndexData);
2717 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2719 TRACE("(%p) No index data set\n", This);
2721 TRACE("Returning %p\n", *ppIndexData);
2726 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2727 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2728 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2729 TRACE("(%p)->(%d)\n", This, BaseIndex);
2731 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2732 TRACE("Application is setting the old value over, nothing to do\n");
2736 This->updateStateBlock->baseVertexIndex = BaseIndex;
2738 if (This->isRecordingState) {
2739 TRACE("Recording... not performing anything\n");
2742 /* The base vertex index affects the stream sources */
2743 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2747 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2748 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2749 TRACE("(%p) : base_index %p\n", This, base_index);
2751 *base_index = This->stateBlock->baseVertexIndex;
2753 TRACE("Returning %u\n", *base_index);
2759 * Get / Set Viewports
2761 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2762 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2764 TRACE("(%p)\n", This);
2765 This->updateStateBlock->changed.viewport = TRUE;
2766 This->updateStateBlock->viewport = *pViewport;
2768 /* Handle recording of state blocks */
2769 if (This->isRecordingState) {
2770 TRACE("Recording... not performing anything\n");
2774 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2775 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2777 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2782 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2783 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2784 TRACE("(%p)\n", This);
2785 *pViewport = This->stateBlock->viewport;
2790 * Get / Set Render States
2791 * TODO: Verify against dx9 definitions
2793 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2795 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2796 DWORD oldValue = This->stateBlock->renderState[State];
2798 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2800 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
2801 This->updateStateBlock->renderState[State] = Value;
2803 /* Handle recording of state blocks */
2804 if (This->isRecordingState) {
2805 TRACE("Recording... not performing anything\n");
2809 /* Compared here and not before the assignment to allow proper stateblock recording */
2810 if(Value == oldValue) {
2811 TRACE("Application is setting the old value over, nothing to do\n");
2813 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2819 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2820 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2821 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2822 *pValue = This->stateBlock->renderState[State];
2827 * Get / Set Sampler States
2828 * TODO: Verify against dx9 definitions
2831 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2832 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2835 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2836 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2838 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2839 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2842 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2843 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2844 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2847 * SetSampler is designed to allow for more than the standard up to 8 textures
2848 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2849 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2851 * http://developer.nvidia.com/object/General_FAQ.html#t6
2853 * There are two new settings for GForce
2855 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2856 * and the texture one:
2857 * GL_MAX_TEXTURE_COORDS_ARB.
2858 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2861 oldValue = This->stateBlock->samplerState[Sampler][Type];
2862 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2863 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
2865 /* Handle recording of state blocks */
2866 if (This->isRecordingState) {
2867 TRACE("Recording... not performing anything\n");
2871 if(oldValue == Value) {
2872 TRACE("Application is setting the old value over, nothing to do\n");
2876 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2881 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2882 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2884 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2885 This, Sampler, debug_d3dsamplerstate(Type), Type);
2887 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2888 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2891 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2892 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2893 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2895 *Value = This->stateBlock->samplerState[Sampler][Type];
2896 TRACE("(%p) : Returning %#x\n", This, *Value);
2901 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2902 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2904 This->updateStateBlock->changed.scissorRect = TRUE;
2905 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2906 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2909 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2911 if(This->isRecordingState) {
2912 TRACE("Recording... not performing anything\n");
2916 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2921 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2922 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2924 *pRect = This->updateStateBlock->scissorRect;
2925 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2929 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2930 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2931 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2933 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2935 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
2936 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
2938 This->updateStateBlock->vertexDecl = pDecl;
2939 This->updateStateBlock->changed.vertexDecl = TRUE;
2941 if (This->isRecordingState) {
2942 TRACE("Recording... not performing anything\n");
2944 } else if(pDecl == oldDecl) {
2945 /* Checked after the assignment to allow proper stateblock recording */
2946 TRACE("Application is setting the old declaration over, nothing to do\n");
2950 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2954 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2955 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2957 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2959 *ppDecl = This->stateBlock->vertexDecl;
2960 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2964 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2965 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2966 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2968 This->updateStateBlock->vertexShader = pShader;
2969 This->updateStateBlock->changed.vertexShader = TRUE;
2971 if (This->isRecordingState) {
2972 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2973 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2974 TRACE("Recording... not performing anything\n");
2976 } else if(oldShader == pShader) {
2977 /* Checked here to allow proper stateblock recording */
2978 TRACE("App is setting the old shader over, nothing to do\n");
2982 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2983 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2984 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2986 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2991 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2992 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2994 if (NULL == ppShader) {
2995 return WINED3DERR_INVALIDCALL;
2997 *ppShader = This->stateBlock->vertexShader;
2998 if( NULL != *ppShader)
2999 IWineD3DVertexShader_AddRef(*ppShader);
3001 TRACE("(%p) : returning %p\n", This, *ppShader);
3005 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3006 IWineD3DDevice *iface,
3008 CONST BOOL *srcData,
3011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3012 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3014 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3015 iface, srcData, start, count);
3017 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3019 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3020 for (i = 0; i < cnt; i++)
3021 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3023 for (i = start; i < cnt + start; ++i) {
3024 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3027 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3032 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3033 IWineD3DDevice *iface,
3038 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3039 int cnt = min(count, MAX_CONST_B - start);
3041 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3042 iface, dstData, start, count);
3044 if (dstData == NULL || cnt < 0)
3045 return WINED3DERR_INVALIDCALL;
3047 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3051 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3052 IWineD3DDevice *iface,
3057 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3058 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3060 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3061 iface, srcData, start, count);
3063 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3065 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3066 for (i = 0; i < cnt; i++)
3067 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3068 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3070 for (i = start; i < cnt + start; ++i) {
3071 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3074 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3079 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3080 IWineD3DDevice *iface,
3085 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3086 int cnt = min(count, MAX_CONST_I - start);
3088 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3089 iface, dstData, start, count);
3091 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= 0)
3092 return WINED3DERR_INVALIDCALL;
3094 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3098 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3099 IWineD3DDevice *iface,
3101 CONST float *srcData,
3104 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3107 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3108 iface, srcData, start, count);
3110 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3111 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3112 return WINED3DERR_INVALIDCALL;
3114 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3116 for (i = 0; i < count; i++)
3117 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3118 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3121 if (!This->isRecordingState)
3123 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3124 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3127 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3128 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3133 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3134 IWineD3DDevice *iface,
3139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3140 int cnt = min(count, This->d3d_vshader_constantF - start);
3142 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3143 iface, dstData, start, count);
3145 if (dstData == NULL || cnt < 0)
3146 return WINED3DERR_INVALIDCALL;
3148 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3152 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3154 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3156 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3160 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3162 DWORD i = This->rev_tex_unit_map[unit];
3163 DWORD j = This->texUnitMap[stage];
3165 This->texUnitMap[stage] = unit;
3166 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3168 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3171 This->rev_tex_unit_map[unit] = stage;
3172 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3174 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3178 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3181 This->fixed_function_usage_map = 0;
3182 for (i = 0; i < MAX_TEXTURES; ++i) {
3183 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3184 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3185 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3186 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3187 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3188 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3189 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3190 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3192 if (color_op == WINED3DTOP_DISABLE) {
3193 /* Not used, and disable higher stages */
3197 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3198 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3199 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3200 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3201 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3202 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3203 This->fixed_function_usage_map |= (1 << i);
3206 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3207 This->fixed_function_usage_map |= (1 << (i + 1));
3212 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3214 unsigned int i, tex;
3217 device_update_fixed_function_usage_map(This);
3218 ffu_map = This->fixed_function_usage_map;
3220 if (This->max_ffp_textures == gl_info->limits.texture_stages
3221 || This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures)
3223 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3225 if (!(ffu_map & 1)) continue;
3227 if (This->texUnitMap[i] != i) {
3228 device_map_stage(This, i, i);
3229 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3230 markTextureStagesDirty(This, i);
3236 /* Now work out the mapping */
3238 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3240 if (!(ffu_map & 1)) continue;
3242 if (This->texUnitMap[i] != tex) {
3243 device_map_stage(This, i, tex);
3244 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3245 markTextureStagesDirty(This, i);
3252 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3254 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3255 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3258 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3259 if (sampler_type[i] && This->texUnitMap[i] != i)
3261 device_map_stage(This, i, i);
3262 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3263 if (i < gl_info->limits.texture_stages)
3265 markTextureStagesDirty(This, i);
3271 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3272 const DWORD *vshader_sampler_tokens, DWORD unit)
3274 DWORD current_mapping = This->rev_tex_unit_map[unit];
3276 /* Not currently used */
3277 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3279 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3280 /* Used by a fragment sampler */
3282 if (!pshader_sampler_tokens) {
3283 /* No pixel shader, check fixed function */
3284 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3287 /* Pixel shader, check the shader's sampler map */
3288 return !pshader_sampler_tokens[current_mapping];
3291 /* Used by a vertex sampler */
3292 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3295 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3297 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3298 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3299 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3300 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3304 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3306 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3307 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3308 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3311 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3312 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3313 if (vshader_sampler_type[i])
3315 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3317 /* Already mapped somewhere */
3321 while (start >= 0) {
3322 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3324 device_map_stage(This, vsampler_idx, start);
3325 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3337 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3339 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3340 BOOL vs = use_vs(This->stateBlock);
3341 BOOL ps = use_ps(This->stateBlock);
3344 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3345 * that would be really messy and require shader recompilation
3346 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3347 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3349 if (ps) device_map_psamplers(This, gl_info);
3350 else device_map_fixed_function_samplers(This, gl_info);
3352 if (vs) device_map_vsamplers(This, ps, gl_info);
3355 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3356 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3357 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3358 This->updateStateBlock->pixelShader = pShader;
3359 This->updateStateBlock->changed.pixelShader = TRUE;
3361 /* Handle recording of state blocks */
3362 if (This->isRecordingState) {
3363 TRACE("Recording... not performing anything\n");
3366 if (This->isRecordingState) {
3367 TRACE("Recording... not performing anything\n");
3368 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3369 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3373 if(pShader == oldShader) {
3374 TRACE("App is setting the old pixel shader over, nothing to do\n");
3378 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3379 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3381 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3382 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3387 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3388 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3390 if (NULL == ppShader) {
3391 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3392 return WINED3DERR_INVALIDCALL;
3395 *ppShader = This->stateBlock->pixelShader;
3396 if (NULL != *ppShader) {
3397 IWineD3DPixelShader_AddRef(*ppShader);
3399 TRACE("(%p) : returning %p\n", This, *ppShader);
3403 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3404 IWineD3DDevice *iface,
3406 CONST BOOL *srcData,
3409 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3410 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3412 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3413 iface, srcData, start, count);
3415 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3417 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3418 for (i = 0; i < cnt; i++)
3419 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3421 for (i = start; i < cnt + start; ++i) {
3422 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3425 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3430 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3431 IWineD3DDevice *iface,
3436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3437 int cnt = min(count, MAX_CONST_B - start);
3439 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3440 iface, dstData, start, count);
3442 if (dstData == NULL || cnt < 0)
3443 return WINED3DERR_INVALIDCALL;
3445 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3449 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3450 IWineD3DDevice *iface,
3455 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3456 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3458 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3459 iface, srcData, start, count);
3461 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3463 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3464 for (i = 0; i < cnt; i++)
3465 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3466 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3468 for (i = start; i < cnt + start; ++i) {
3469 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3472 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3477 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3478 IWineD3DDevice *iface,
3483 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3484 int cnt = min(count, MAX_CONST_I - start);
3486 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3487 iface, dstData, start, count);
3489 if (dstData == NULL || cnt < 0)
3490 return WINED3DERR_INVALIDCALL;
3492 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3496 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3497 IWineD3DDevice *iface,
3499 CONST float *srcData,
3502 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3505 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3506 iface, srcData, start, count);
3508 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3509 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3510 return WINED3DERR_INVALIDCALL;
3512 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3514 for (i = 0; i < count; i++)
3515 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3516 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3519 if (!This->isRecordingState)
3521 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3522 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3525 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3526 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3531 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3532 IWineD3DDevice *iface,
3537 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3538 int cnt = min(count, This->d3d_pshader_constantF - start);
3540 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3541 iface, dstData, start, count);
3543 if (dstData == NULL || cnt < 0)
3544 return WINED3DERR_INVALIDCALL;
3546 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3550 /* Context activation is done by the caller. */
3551 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3552 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3553 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3556 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3557 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3560 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3564 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3566 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3569 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3571 ERR("Source has no position mask\n");
3572 return WINED3DERR_INVALIDCALL;
3575 /* We might access VBOs from this code, so hold the lock */
3578 if (dest->resource.allocatedMemory == NULL) {
3579 buffer_get_sysmem(dest);
3582 /* Get a pointer into the destination vbo(create one if none exists) and
3583 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3585 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3587 dest->flags |= WINED3D_BUFFER_CREATEBO;
3588 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3591 if (dest->buffer_object)
3593 unsigned char extrabytes = 0;
3594 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3595 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3596 * this may write 4 extra bytes beyond the area that should be written
3598 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3599 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3600 if(!dest_conv_addr) {
3601 ERR("Out of memory\n");
3602 /* Continue without storing converted vertices */
3604 dest_conv = dest_conv_addr;
3608 * a) WINED3DRS_CLIPPING is enabled
3609 * b) WINED3DVOP_CLIP is passed
3611 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3612 static BOOL warned = FALSE;
3614 * The clipping code is not quite correct. Some things need
3615 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3616 * so disable clipping for now.
3617 * (The graphics in Half-Life are broken, and my processvertices
3618 * test crashes with IDirect3DDevice3)
3624 FIXME("Clipping is broken and disabled for now\n");
3626 } else doClip = FALSE;
3627 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3629 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3632 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3633 WINED3DTS_PROJECTION,
3635 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3636 WINED3DTS_WORLDMATRIX(0),
3639 TRACE("View mat:\n");
3640 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);
3641 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);
3642 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);
3643 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);
3645 TRACE("Proj mat:\n");
3646 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);
3647 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);
3648 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);
3649 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);
3651 TRACE("World mat:\n");
3652 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);
3653 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);
3654 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);
3655 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);
3657 /* Get the viewport */
3658 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3659 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3660 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3662 multiply_matrix(&mat,&view_mat,&world_mat);
3663 multiply_matrix(&mat,&proj_mat,&mat);
3665 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3667 for (i = 0; i < dwCount; i+= 1) {
3668 unsigned int tex_index;
3670 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3671 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3672 /* The position first */
3673 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3674 const float *p = (const float *)(element->data + i * element->stride);
3676 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3678 /* Multiplication with world, view and projection matrix */
3679 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);
3680 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);
3681 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);
3682 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);
3684 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3686 /* WARNING: The following things are taken from d3d7 and were not yet checked
3687 * against d3d8 or d3d9!
3690 /* Clipping conditions: From msdn
3692 * A vertex is clipped if it does not match the following requirements
3696 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3698 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3699 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3704 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3705 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3708 /* "Normal" viewport transformation (not clipped)
3709 * 1) The values are divided by rhw
3710 * 2) The y axis is negative, so multiply it with -1
3711 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3712 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3713 * 4) Multiply x with Width/2 and add Width/2
3714 * 5) The same for the height
3715 * 6) Add the viewpoint X and Y to the 2D coordinates and
3716 * The minimum Z value to z
3717 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3719 * Well, basically it's simply a linear transformation into viewport
3731 z *= vp.MaxZ - vp.MinZ;
3733 x += vp.Width / 2 + vp.X;
3734 y += vp.Height / 2 + vp.Y;
3739 /* That vertex got clipped
3740 * Contrary to OpenGL it is not dropped completely, it just
3741 * undergoes a different calculation.
3743 TRACE("Vertex got clipped\n");
3750 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3751 * outside of the main vertex buffer memory. That needs some more
3756 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3759 ( (float *) dest_ptr)[0] = x;
3760 ( (float *) dest_ptr)[1] = y;
3761 ( (float *) dest_ptr)[2] = z;
3762 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3764 dest_ptr += 3 * sizeof(float);
3766 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3767 dest_ptr += sizeof(float);
3772 ( (float *) dest_conv)[0] = x * w;
3773 ( (float *) dest_conv)[1] = y * w;
3774 ( (float *) dest_conv)[2] = z * w;
3775 ( (float *) dest_conv)[3] = w;
3777 dest_conv += 3 * sizeof(float);
3779 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3780 dest_conv += sizeof(float);
3784 if (DestFVF & WINED3DFVF_PSIZE) {
3785 dest_ptr += sizeof(DWORD);
3786 if(dest_conv) dest_conv += sizeof(DWORD);
3788 if (DestFVF & WINED3DFVF_NORMAL) {
3789 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
3790 const float *normal = (const float *)(element->data + i * element->stride);
3791 /* AFAIK this should go into the lighting information */
3792 FIXME("Didn't expect the destination to have a normal\n");
3793 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3795 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3799 if (DestFVF & WINED3DFVF_DIFFUSE) {
3800 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
3801 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
3802 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
3804 static BOOL warned = FALSE;
3807 ERR("No diffuse color in source, but destination has one\n");
3811 *( (DWORD *) dest_ptr) = 0xffffffff;
3812 dest_ptr += sizeof(DWORD);
3815 *( (DWORD *) dest_conv) = 0xffffffff;
3816 dest_conv += sizeof(DWORD);
3820 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3822 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3823 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3824 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3825 dest_conv += sizeof(DWORD);
3830 if (DestFVF & WINED3DFVF_SPECULAR)
3832 /* What's the color value in the feedback buffer? */
3833 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
3834 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
3835 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
3837 static BOOL warned = FALSE;
3840 ERR("No specular color in source, but destination has one\n");
3844 *( (DWORD *) dest_ptr) = 0xFF000000;
3845 dest_ptr += sizeof(DWORD);
3848 *( (DWORD *) dest_conv) = 0xFF000000;
3849 dest_conv += sizeof(DWORD);
3853 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3855 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3856 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3857 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3858 dest_conv += sizeof(DWORD);
3863 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3864 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
3865 const float *tex_coord = (const float *)(element->data + i * element->stride);
3866 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
3868 ERR("No source texture, but destination requests one\n");
3869 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3870 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3873 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3875 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3882 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
3883 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3884 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3885 dwCount * get_flexible_vertex_size(DestFVF),
3887 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3888 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3895 #undef copy_and_next
3897 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
3898 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
3901 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3902 struct wined3d_stream_info stream_info;
3903 struct wined3d_context *context;
3904 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3907 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3910 ERR("Output vertex declaration not implemented yet\n");
3913 /* Need any context to write to the vbo. */
3914 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
3916 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3917 * control the streamIsUP flag, thus restore it afterwards.
3919 This->stateBlock->streamIsUP = FALSE;
3920 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
3921 This->stateBlock->streamIsUP = streamWasUP;
3923 if(vbo || SrcStartIndex) {
3925 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
3926 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
3928 * Also get the start index in, but only loop over all elements if there's something to add at all.
3930 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
3932 struct wined3d_stream_info_element *e;
3934 if (!(stream_info.use_map & (1 << i))) continue;
3936 e = &stream_info.elements[i];
3937 if (e->buffer_object)
3939 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
3940 e->buffer_object = 0;
3941 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
3943 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
3944 vb->buffer_object = 0;
3947 if (e->data) e->data += e->stride * SrcStartIndex;
3951 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
3952 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
3954 context_release(context);
3960 * Get / Set Texture Stage States
3961 * TODO: Verify against dx9 definitions
3963 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3964 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3965 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3966 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3968 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3970 if (Stage >= gl_info->limits.texture_stages)
3972 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
3973 Stage, gl_info->limits.texture_stages - 1);
3977 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
3978 This->updateStateBlock->textureState[Stage][Type] = Value;
3980 if (This->isRecordingState) {
3981 TRACE("Recording... not performing anything\n");
3985 /* Checked after the assignments to allow proper stateblock recording */
3986 if(oldValue == Value) {
3987 TRACE("App is setting the old value over, nothing to do\n");
3991 if(Stage > This->stateBlock->lowest_disabled_stage &&
3992 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3993 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3994 * Changes in other states are important on disabled stages too
3999 if(Type == WINED3DTSS_COLOROP) {
4002 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4003 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4004 * they have to be disabled
4006 * The current stage is dirtified below.
4008 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4009 TRACE("Additionally dirtifying stage %u\n", i);
4010 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4012 This->stateBlock->lowest_disabled_stage = Stage;
4013 TRACE("New lowest disabled: %u\n", Stage);
4014 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4015 /* Previously disabled stage enabled. Stages above it may need enabling
4016 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4017 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4019 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4022 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4024 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4027 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4028 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4030 This->stateBlock->lowest_disabled_stage = i;
4031 TRACE("New lowest disabled: %u\n", i);
4035 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4040 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4041 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4042 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4043 *pValue = This->updateStateBlock->textureState[Stage][Type];
4050 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4051 DWORD stage, IWineD3DBaseTexture *texture)
4053 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4054 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4055 IWineD3DBaseTexture *prev;
4057 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4059 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4060 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4062 /* Windows accepts overflowing this array... we do not. */
4063 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
4065 WARN("Ignoring invalid stage %u.\n", stage);
4069 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4070 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4072 WARN("Rejecting attempt to set scratch texture.\n");
4073 return WINED3DERR_INVALIDCALL;
4076 This->updateStateBlock->changed.textures |= 1 << stage;
4078 prev = This->updateStateBlock->textures[stage];
4079 TRACE("Previous texture %p.\n", prev);
4081 if (texture == prev)
4083 TRACE("App is setting the same texture again, nothing to do.\n");
4087 TRACE("Setting new texture to %p.\n", texture);
4088 This->updateStateBlock->textures[stage] = texture;
4090 if (This->isRecordingState)
4092 TRACE("Recording... not performing anything\n");
4094 if (texture) IWineD3DBaseTexture_AddRef(texture);
4095 if (prev) IWineD3DBaseTexture_Release(prev);
4102 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4103 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4104 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
4106 IWineD3DBaseTexture_AddRef(texture);
4108 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
4110 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4113 if (!prev && stage < gl_info->limits.texture_stages)
4115 /* The source arguments for color and alpha ops have different
4116 * meanings when a NULL texture is bound, so the COLOROP and
4117 * ALPHAOP have to be dirtified. */
4118 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4119 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4122 if (bind_count == 1) t->baseTexture.sampler = stage;
4127 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4128 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4130 IWineD3DBaseTexture_Release(prev);
4132 if (!texture && stage < gl_info->limits.texture_stages)
4134 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4135 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4138 if (bind_count && t->baseTexture.sampler == stage)
4142 /* Search for other stages the texture is bound to. Shouldn't
4143 * happen if applications bind textures to a single stage only. */
4144 TRACE("Searching for other stages the texture is bound to.\n");
4145 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4147 if (This->updateStateBlock->textures[i] == prev)
4149 TRACE("Texture is also bound to stage %u.\n", i);
4150 t->baseTexture.sampler = i;
4157 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4162 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4163 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4165 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4167 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4168 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4171 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4172 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4173 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4176 *ppTexture=This->stateBlock->textures[Stage];
4178 IWineD3DBaseTexture_AddRef(*ppTexture);
4180 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4188 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4189 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4191 IWineD3DSwapChain *swapchain;
4194 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4195 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4197 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4200 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4204 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4205 IWineD3DSwapChain_Release(swapchain);
4208 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4215 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4216 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4217 WARN("(%p) : stub, calling idirect3d for now\n", This);
4218 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4221 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4222 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4223 IWineD3DSwapChain *swapChain;
4226 if(iSwapChain > 0) {
4227 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4228 if (hr == WINED3D_OK) {
4229 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4230 IWineD3DSwapChain_Release(swapChain);
4232 FIXME("(%p) Error getting display mode\n", This);
4235 /* Don't read the real display mode,
4236 but return the stored mode instead. X11 can't change the color
4237 depth, and some apps are pretty angry if they SetDisplayMode from
4238 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4240 Also don't relay to the swapchain because with ddraw it's possible
4241 that there isn't a swapchain at all */
4242 pMode->Width = This->ddraw_width;
4243 pMode->Height = This->ddraw_height;
4244 pMode->Format = This->ddraw_format;
4245 pMode->RefreshRate = 0;
4253 * Stateblock related functions
4256 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4257 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4258 IWineD3DStateBlock *stateblock;
4261 TRACE("(%p)\n", This);
4263 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4265 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4266 if (FAILED(hr)) return hr;
4268 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4269 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4270 This->isRecordingState = TRUE;
4272 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4277 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4278 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4279 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4281 if (!This->isRecordingState) {
4282 WARN("(%p) not recording! returning error\n", This);
4283 *ppStateBlock = NULL;
4284 return WINED3DERR_INVALIDCALL;
4287 stateblock_init_contained_states(object);
4289 *ppStateBlock = (IWineD3DStateBlock*) object;
4290 This->isRecordingState = FALSE;
4291 This->updateStateBlock = This->stateBlock;
4292 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4293 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4294 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4299 * Scene related functions
4301 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4302 /* At the moment we have no need for any functionality at the beginning
4304 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4305 TRACE("(%p)\n", This);
4308 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4309 return WINED3DERR_INVALIDCALL;
4311 This->inScene = TRUE;
4315 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4317 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4318 struct wined3d_context *context;
4320 TRACE("(%p)\n", This);
4322 if(!This->inScene) {
4323 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4324 return WINED3DERR_INVALIDCALL;
4327 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
4328 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4330 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4332 context_release(context);
4334 This->inScene = FALSE;
4338 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4339 const RECT *pSourceRect, const RECT *pDestRect,
4340 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4342 IWineD3DSwapChain *swapChain = NULL;
4344 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4346 TRACE("iface %p.\n", iface);
4348 for(i = 0 ; i < swapchains ; i ++) {
4350 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4351 TRACE("presentinng chain %d, %p\n", i, swapChain);
4352 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4353 IWineD3DSwapChain_Release(swapChain);
4359 static BOOL is_full_clear(IWineD3DSurfaceImpl *target, const RECT *draw_rect, const RECT *clear_rect)
4361 /* partial draw rect */
4362 if (draw_rect->left || draw_rect->top
4363 || draw_rect->right < target->currentDesc.Width
4364 || draw_rect->bottom < target->currentDesc.Height)
4367 /* partial clear rect */
4368 if (clear_rect && (clear_rect->left > 0 || clear_rect->top > 0
4369 || clear_rect->right < target->currentDesc.Width
4370 || clear_rect->bottom < target->currentDesc.Height))
4376 static void prepare_ds_clear(IWineD3DSurfaceImpl *ds, struct wined3d_context *context,
4377 DWORD location, const RECT *draw_rect, UINT rect_count, const RECT *clear_rect)
4379 RECT current_rect, r;
4381 if (ds->Flags & location)
4382 SetRect(¤t_rect, 0, 0,
4383 ds->ds_current_size.cx,
4384 ds->ds_current_size.cy);
4386 SetRectEmpty(¤t_rect);
4388 IntersectRect(&r, draw_rect, ¤t_rect);
4389 if (EqualRect(&r, draw_rect))
4391 /* current_rect ⊇ draw_rect, modify only. */
4392 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
4396 if (EqualRect(&r, ¤t_rect))
4398 /* draw_rect ⊇ current_rect, test if we're doing a full clear. */
4402 /* Full clear, modify only. */
4403 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
4409 /* Multiple clear rects, full load. Strictly speaking this can
4410 * also be a full draw_rect clear, but it's probably rare enough
4411 * that we don't care. */
4412 surface_load_ds_location(ds, context, location);
4413 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
4417 IntersectRect(&r, draw_rect, clear_rect);
4418 if (EqualRect(&r, draw_rect))
4420 /* clear_rect ⊇ draw_rect, modify only. */
4421 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
4427 surface_load_ds_location(ds, context, location);
4428 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
4431 /* Not called from the VTable (internal subroutine) */
4432 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4433 const WINED3DRECT *pRects, DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil)
4435 const RECT *clear_rect = (Count > 0 && pRects) ? (const RECT *)pRects : NULL;
4436 IWineD3DSurfaceImpl *depth_stencil = This->depth_stencil;
4437 GLbitfield glMask = 0;
4439 UINT drawable_width, drawable_height;
4440 struct wined3d_context *context;
4443 device_get_draw_rect(This, &draw_rect);
4445 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4446 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4447 * for the cleared parts, and the untouched parts.
4449 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4450 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4451 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4452 * checking all this if the dest surface is in the drawable anyway.
4454 if (Flags & WINED3DCLEAR_TARGET && !(target->Flags & SFLAG_INDRAWABLE))
4456 if (!is_full_clear(target, &draw_rect, clear_rect))
4457 IWineD3DSurface_LoadLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, NULL);
4460 context = context_acquire(This, target, CTXUSAGE_CLEAR);
4461 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
4463 if (!surface_is_offscreen(target))
4465 TRACE("Surface %p is onscreen\n", target);
4468 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
4469 context_set_draw_buffer(context, surface_get_gl_buffer(target));
4474 TRACE("Surface %p is offscreen\n", target);
4477 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
4478 context_attach_surface_fbo(context, GL_FRAMEBUFFER, 0, target);
4479 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, depth_stencil, TRUE);
4484 if (!context->valid)
4486 context_release(context);
4487 WARN("Invalid context, skipping clear.\n");
4491 target->get_drawable_size(context, &drawable_width, &drawable_height);
4495 /* Only set the values up once, as they are not changing */
4496 if (Flags & WINED3DCLEAR_STENCIL)
4498 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
4500 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
4501 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE));
4504 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
4505 glClearStencil(Stencil);
4506 checkGLcall("glClearStencil");
4507 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4510 if (Flags & WINED3DCLEAR_ZBUFFER)
4512 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4514 if (location == SFLAG_DS_ONSCREEN && depth_stencil != This->onscreen_depth_stencil)
4515 device_switch_onscreen_ds(This, context, depth_stencil);
4516 prepare_ds_clear(depth_stencil, context, location, &draw_rect, Count, clear_rect);
4518 glDepthMask(GL_TRUE);
4519 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4521 checkGLcall("glClearDepth");
4522 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4525 if (Flags & WINED3DCLEAR_TARGET)
4527 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
4529 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4530 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
4531 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
4532 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
4533 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
4534 glClearColor(D3DCOLOR_R(Color), D3DCOLOR_G(Color), D3DCOLOR_B(Color), D3DCOLOR_A(Color));
4535 checkGLcall("glClearColor");
4536 glMask = glMask | GL_COLOR_BUFFER_BIT;
4541 if (context->render_offscreen)
4543 glScissor(draw_rect.left, draw_rect.top,
4544 draw_rect.right - draw_rect.left, draw_rect.bottom - draw_rect.top);
4548 glScissor(draw_rect.left, drawable_height - draw_rect.bottom,
4549 draw_rect.right - draw_rect.left, draw_rect.bottom - draw_rect.top);
4551 checkGLcall("glScissor");
4553 checkGLcall("glClear");
4559 /* Now process each rect in turn. */
4560 for (i = 0; i < Count; ++i)
4562 /* Note gl uses lower left, width/height */
4563 IntersectRect(¤t_rect, &draw_rect, &clear_rect[i]);
4565 TRACE("clear_rect[%u] %s, current_rect %s.\n", i,
4566 wine_dbgstr_rect(&clear_rect[i]),
4567 wine_dbgstr_rect(¤t_rect));
4569 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4570 * The rectangle is not cleared, no error is returned, but further rectanlges are
4571 * still cleared if they are valid. */
4572 if (current_rect.left > current_rect.right || current_rect.top > current_rect.bottom)
4574 TRACE("Rectangle with negative dimensions, ignoring.\n");
4578 if (context->render_offscreen)
4580 glScissor(current_rect.left, current_rect.top,
4581 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
4585 glScissor(current_rect.left, drawable_height - current_rect.bottom,
4586 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
4588 checkGLcall("glScissor");
4591 checkGLcall("glClear");
4597 if (wined3d_settings.strict_draw_ordering || ((target->Flags & SFLAG_SWAPCHAIN)
4598 && ((IWineD3DSwapChainImpl *)target->container)->front_buffer == target))
4599 wglFlush(); /* Flush to ensure ordering across contexts. */
4601 context_release(context);
4606 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count,
4607 const WINED3DRECT *pRects, DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil)
4609 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4611 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4612 Count, pRects, Flags, Color, Z, Stencil);
4614 if (Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && !This->depth_stencil)
4616 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4617 /* TODO: What about depth stencil buffers without stencil bits? */
4618 return WINED3DERR_INVALIDCALL;
4621 return IWineD3DDeviceImpl_ClearSurface(This, This->render_targets[0], Count, pRects, Flags, Color, Z, Stencil);
4628 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4629 WINED3DPRIMITIVETYPE primitive_type)
4631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4633 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4635 This->updateStateBlock->changed.primitive_type = TRUE;
4636 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4639 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4640 WINED3DPRIMITIVETYPE *primitive_type)
4642 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4644 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4646 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4648 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4651 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4653 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4655 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4657 if(!This->stateBlock->vertexDecl) {
4658 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4659 return WINED3DERR_INVALIDCALL;
4662 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4663 if(This->stateBlock->streamIsUP) {
4664 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4665 This->stateBlock->streamIsUP = FALSE;
4668 if(This->stateBlock->loadBaseVertexIndex != 0) {
4669 This->stateBlock->loadBaseVertexIndex = 0;
4670 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4672 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4673 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4677 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4679 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4681 IWineD3DBuffer *pIB;
4684 pIB = This->stateBlock->pIndexData;
4686 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4687 * without an index buffer set. (The first time at least...)
4688 * D3D8 simply dies, but I doubt it can do much harm to return
4689 * D3DERR_INVALIDCALL there as well. */
4690 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4691 return WINED3DERR_INVALIDCALL;
4694 if(!This->stateBlock->vertexDecl) {
4695 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4696 return WINED3DERR_INVALIDCALL;
4699 if(This->stateBlock->streamIsUP) {
4700 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4701 This->stateBlock->streamIsUP = FALSE;
4703 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4705 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4707 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4713 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4714 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4715 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4718 drawPrimitive(iface, index_count, startIndex, idxStride,
4719 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4724 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4725 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4727 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4730 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4731 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4733 if(!This->stateBlock->vertexDecl) {
4734 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4735 return WINED3DERR_INVALIDCALL;
4738 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4739 vb = This->stateBlock->streamSource[0];
4740 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4741 if (vb) IWineD3DBuffer_Release(vb);
4742 This->stateBlock->streamOffset[0] = 0;
4743 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4744 This->stateBlock->streamIsUP = TRUE;
4745 This->stateBlock->loadBaseVertexIndex = 0;
4747 /* TODO: Only mark dirty if drawing from a different UP address */
4748 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4750 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4752 /* MSDN specifies stream zero settings must be set to NULL */
4753 This->stateBlock->streamStride[0] = 0;
4754 This->stateBlock->streamSource[0] = NULL;
4756 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4757 * the new stream sources or use UP drawing again
4762 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4763 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4764 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4767 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4771 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4772 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4774 if(!This->stateBlock->vertexDecl) {
4775 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4776 return WINED3DERR_INVALIDCALL;
4779 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4785 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4786 vb = This->stateBlock->streamSource[0];
4787 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4788 if (vb) IWineD3DBuffer_Release(vb);
4789 This->stateBlock->streamIsUP = TRUE;
4790 This->stateBlock->streamOffset[0] = 0;
4791 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4793 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4794 This->stateBlock->baseVertexIndex = 0;
4795 This->stateBlock->loadBaseVertexIndex = 0;
4796 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4797 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4798 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4800 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4802 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4803 This->stateBlock->streamSource[0] = NULL;
4804 This->stateBlock->streamStride[0] = 0;
4805 ib = This->stateBlock->pIndexData;
4807 IWineD3DBuffer_Release(ib);
4808 This->stateBlock->pIndexData = NULL;
4810 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4811 * SetStreamSource to specify a vertex buffer
4817 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4818 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4820 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4822 /* Mark the state dirty until we have nicer tracking
4823 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4826 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4827 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4828 This->stateBlock->baseVertexIndex = 0;
4829 This->up_strided = DrawPrimStrideData;
4830 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4831 This->up_strided = NULL;
4835 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4836 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4837 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4839 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4840 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4842 /* Mark the state dirty until we have nicer tracking
4843 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4846 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4847 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4848 This->stateBlock->streamIsUP = TRUE;
4849 This->stateBlock->baseVertexIndex = 0;
4850 This->up_strided = DrawPrimStrideData;
4851 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4852 This->up_strided = NULL;
4856 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4857 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4858 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4860 WINED3DLOCKED_BOX src;
4861 WINED3DLOCKED_BOX dst;
4864 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4865 iface, pSourceVolume, pDestinationVolume);
4867 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4868 * dirtification to improve loading performance.
4870 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4871 if(FAILED(hr)) return hr;
4872 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4874 IWineD3DVolume_UnlockBox(pSourceVolume);
4878 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4880 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4882 IWineD3DVolume_UnlockBox(pSourceVolume);
4884 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4889 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4890 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4892 unsigned int level_count, i;
4893 WINED3DRESOURCETYPE type;
4896 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4898 /* Verify that the source and destination textures are non-NULL. */
4899 if (!src_texture || !dst_texture)
4901 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4902 return WINED3DERR_INVALIDCALL;
4905 if (src_texture == dst_texture)
4907 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4908 return WINED3DERR_INVALIDCALL;
4911 /* Verify that the source and destination textures are the same type. */
4912 type = IWineD3DBaseTexture_GetType(src_texture);
4913 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4915 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4916 return WINED3DERR_INVALIDCALL;
4919 /* Check that both textures have the identical numbers of levels. */
4920 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4921 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4923 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4924 return WINED3DERR_INVALIDCALL;
4927 /* Make sure that the destination texture is loaded. */
4928 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4930 /* Update every surface level of the texture. */
4933 case WINED3DRTYPE_TEXTURE:
4935 IWineD3DSurface *src_surface;
4936 IWineD3DSurface *dst_surface;
4938 for (i = 0; i < level_count; ++i)
4940 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4941 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4942 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4943 IWineD3DSurface_Release(dst_surface);
4944 IWineD3DSurface_Release(src_surface);
4947 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4954 case WINED3DRTYPE_CUBETEXTURE:
4956 IWineD3DSurface *src_surface;
4957 IWineD3DSurface *dst_surface;
4958 WINED3DCUBEMAP_FACES face;
4960 for (i = 0; i < level_count; ++i)
4962 /* Update each cube face. */
4963 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4965 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
4966 face, i, &src_surface);
4967 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4968 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
4969 face, i, &dst_surface);
4970 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4971 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4972 IWineD3DSurface_Release(dst_surface);
4973 IWineD3DSurface_Release(src_surface);
4976 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4984 case WINED3DRTYPE_VOLUMETEXTURE:
4986 IWineD3DVolume *src_volume;
4987 IWineD3DVolume *dst_volume;
4989 for (i = 0; i < level_count; ++i)
4991 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
4992 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
4993 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
4994 IWineD3DVolume_Release(dst_volume);
4995 IWineD3DVolume_Release(src_volume);
4998 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
5006 FIXME("Unsupported texture type %#x.\n", type);
5007 return WINED3DERR_INVALIDCALL;
5013 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5014 IWineD3DSwapChain *swapChain;
5016 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5017 if(hr == WINED3D_OK) {
5018 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5019 IWineD3DSwapChain_Release(swapChain);
5024 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5025 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5026 IWineD3DBaseTextureImpl *texture;
5029 TRACE("(%p) : %p\n", This, pNumPasses);
5031 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5032 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5033 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5034 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5036 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5037 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5038 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5041 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5042 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5044 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5045 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5048 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5049 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5052 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5053 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5054 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5059 /* return a sensible default */
5062 TRACE("returning D3D_OK\n");
5066 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5070 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5072 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5073 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
5074 || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
5076 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5081 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5082 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5085 PALETTEENTRY **palettes;
5087 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5089 if (PaletteNumber >= MAX_PALETTES) {
5090 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5091 return WINED3DERR_INVALIDCALL;
5094 if (PaletteNumber >= This->NumberOfPalettes) {
5095 NewSize = This->NumberOfPalettes;
5098 } while(PaletteNumber >= NewSize);
5099 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5101 ERR("Out of memory!\n");
5102 return E_OUTOFMEMORY;
5104 This->palettes = palettes;
5105 This->NumberOfPalettes = NewSize;
5108 if (!This->palettes[PaletteNumber]) {
5109 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5110 if (!This->palettes[PaletteNumber]) {
5111 ERR("Out of memory!\n");
5112 return E_OUTOFMEMORY;
5116 for (j = 0; j < 256; ++j) {
5117 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5118 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5119 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5120 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5122 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5123 TRACE("(%p) : returning\n", This);
5127 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5128 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5130 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5131 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5132 /* What happens in such situation isn't documented; Native seems to silently abort
5133 on such conditions. Return Invalid Call. */
5134 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5135 return WINED3DERR_INVALIDCALL;
5137 for (j = 0; j < 256; ++j) {
5138 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5139 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5140 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5141 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5143 TRACE("(%p) : returning\n", This);
5147 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5148 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5149 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5150 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5151 (tested with reference rasterizer). Return Invalid Call. */
5152 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5153 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5154 return WINED3DERR_INVALIDCALL;
5156 /*TODO: stateblocks */
5157 if (This->currentPalette != PaletteNumber) {
5158 This->currentPalette = PaletteNumber;
5159 dirtify_p8_texture_samplers(This);
5161 TRACE("(%p) : returning\n", This);
5165 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5166 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5167 if (PaletteNumber == NULL) {
5168 WARN("(%p) : returning Invalid Call\n", This);
5169 return WINED3DERR_INVALIDCALL;
5171 /*TODO: stateblocks */
5172 *PaletteNumber = This->currentPalette;
5173 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5177 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5178 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5182 FIXME("(%p) : stub\n", This);
5186 This->softwareVertexProcessing = bSoftware;
5191 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5196 FIXME("(%p) : stub\n", This);
5199 return This->softwareVertexProcessing;
5202 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5203 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5205 IWineD3DSwapChain *swapchain;
5208 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5209 iface, swapchain_idx, raster_status);
5211 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5214 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5218 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5219 IWineD3DSwapChain_Release(swapchain);
5222 WARN("Failed to get raster status, hr %#x.\n", hr);
5229 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5232 if(nSegments != 0.0f) {
5235 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5242 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5247 FIXME("iface %p stub!\n", iface);
5253 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5254 IWineD3DSurface *src_surface, const RECT *src_rect,
5255 IWineD3DSurface *dst_surface, const POINT *dst_point)
5257 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5258 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5259 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5260 const struct wined3d_format_desc *src_format;
5261 const struct wined3d_format_desc *dst_format;
5262 struct wined3d_context *context;
5263 const unsigned char *data;
5264 UINT update_w, update_h;
5265 CONVERT_TYPES convert;
5269 struct wined3d_format_desc dummy_desc;
5271 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5272 iface, src_surface, wine_dbgstr_rect(src_rect),
5273 dst_surface, wine_dbgstr_point(dst_point));
5275 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5277 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5278 src_surface, dst_surface);
5279 return WINED3DERR_INVALIDCALL;
5282 src_format = src_impl->resource.format_desc;
5283 dst_format = dst_impl->resource.format_desc;
5285 if (src_format->format != dst_format->format)
5287 WARN("Source and destination surfaces should have the same format.\n");
5288 return WINED3DERR_INVALIDCALL;
5291 dst_x = dst_point ? dst_point->x : 0;
5292 dst_y = dst_point ? dst_point->y : 0;
5294 /* This call loads the OpenGL surface directly, instead of copying the
5295 * surface to the destination's sysmem copy. If surface conversion is
5296 * needed, use BltFast instead to copy in sysmem and use regular surface
5298 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy_desc, &convert);
5299 if (convert != NO_CONVERSION)
5300 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5302 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5305 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5306 checkGLcall("glActiveTextureARB");
5309 /* Make sure the surface is loaded and up to date */
5310 surface_internal_preload(dst_impl, SRGB_RGB);
5311 IWineD3DSurface_BindTexture(dst_surface, FALSE);
5313 src_w = src_impl->currentDesc.Width;
5314 src_h = src_impl->currentDesc.Height;
5315 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5316 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5318 data = IWineD3DSurface_GetData(src_surface);
5319 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5323 if (dst_format->Flags & WINED3DFMT_FLAG_COMPRESSED)
5325 UINT row_length = (update_w / src_format->block_width) * src_format->block_byte_count;
5326 UINT row_count = update_h / src_format->block_height;
5327 UINT src_pitch = IWineD3DSurface_GetPitch(src_surface);
5331 data += (src_rect->top / src_format->block_height) * src_pitch;
5332 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5335 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5336 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5337 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5339 if (row_length == src_pitch)
5341 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5342 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5348 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5349 * can't use the unpack row length like below. */
5350 for (row = 0, y = dst_y; row < row_count; ++row)
5352 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5353 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5354 y += src_format->block_height;
5358 checkGLcall("glCompressedTexSubImage2DARB");
5364 data += src_rect->top * src_w * src_format->byte_count;
5365 data += src_rect->left * src_format->byte_count;
5368 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5369 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5370 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5372 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5373 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5374 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5375 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5376 checkGLcall("glTexSubImage2D");
5380 context_release(context);
5382 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INTEXTURE, TRUE);
5383 sampler = This->rev_tex_unit_map[0];
5384 if (sampler != WINED3D_UNMAPPED_STAGE)
5386 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5392 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5393 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5394 struct WineD3DRectPatch *patch;
5395 GLenum old_primitive_type;
5399 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5401 if(!(Handle || pRectPatchInfo)) {
5402 /* TODO: Write a test for the return value, thus the FIXME */
5403 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5404 return WINED3DERR_INVALIDCALL;
5408 i = PATCHMAP_HASHFUNC(Handle);
5410 LIST_FOR_EACH(e, &This->patches[i]) {
5411 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5412 if(patch->Handle == Handle) {
5419 TRACE("Patch does not exist. Creating a new one\n");
5420 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5421 patch->Handle = Handle;
5422 list_add_head(&This->patches[i], &patch->entry);
5424 TRACE("Found existing patch %p\n", patch);
5427 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5428 * attributes we have to tesselate, read back, and draw. This needs a patch
5429 * management structure instance. Create one.
5431 * A possible improvement is to check if a vertex shader is used, and if not directly
5434 FIXME("Drawing an uncached patch. This is slow\n");
5435 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5438 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5439 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5440 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5442 TRACE("Tesselation density or patch info changed, retesselating\n");
5444 if(pRectPatchInfo) {
5445 patch->RectPatchInfo = *pRectPatchInfo;
5447 patch->numSegs[0] = pNumSegs[0];
5448 patch->numSegs[1] = pNumSegs[1];
5449 patch->numSegs[2] = pNumSegs[2];
5450 patch->numSegs[3] = pNumSegs[3];
5452 hr = tesselate_rectpatch(This, patch);
5454 WARN("Patch tesselation failed\n");
5456 /* Do not release the handle to store the params of the patch */
5458 HeapFree(GetProcessHeap(), 0, patch);
5464 This->currentPatch = patch;
5465 old_primitive_type = This->stateBlock->gl_primitive_type;
5466 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5467 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5468 This->stateBlock->gl_primitive_type = old_primitive_type;
5469 This->currentPatch = NULL;
5471 /* Destroy uncached patches */
5473 HeapFree(GetProcessHeap(), 0, patch->mem);
5474 HeapFree(GetProcessHeap(), 0, patch);
5479 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5480 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5482 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5483 iface, handle, segment_count, patch_info);
5488 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5489 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5491 struct WineD3DRectPatch *patch;
5493 TRACE("(%p) Handle(%d)\n", This, Handle);
5495 i = PATCHMAP_HASHFUNC(Handle);
5496 LIST_FOR_EACH(e, &This->patches[i]) {
5497 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5498 if(patch->Handle == Handle) {
5499 TRACE("Deleting patch %p\n", patch);
5500 list_remove(&patch->entry);
5501 HeapFree(GetProcessHeap(), 0, patch->mem);
5502 HeapFree(GetProcessHeap(), 0, patch);
5507 /* TODO: Write a test for the return value */
5508 FIXME("Attempt to destroy nonexistent patch\n");
5509 return WINED3DERR_INVALIDCALL;
5512 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurfaceImpl *surface,
5513 const WINED3DRECT *rect, const float color[4])
5515 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5516 struct wined3d_context *context;
5518 if (rect) IWineD3DSurface_LoadLocation((IWineD3DSurface *)surface, SFLAG_INDRAWABLE, NULL);
5519 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)surface, SFLAG_INDRAWABLE, TRUE);
5521 if (!surface_is_offscreen(surface))
5523 TRACE("Surface %p is onscreen\n", surface);
5525 context = context_acquire(This, surface, CTXUSAGE_RESOURCELOAD);
5527 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
5528 context_set_draw_buffer(context, surface_get_gl_buffer(surface));
5532 TRACE("Surface %p is offscreen\n", surface);
5534 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5536 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
5537 context_attach_surface_fbo(context, GL_FRAMEBUFFER, 0, surface);
5538 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, NULL, FALSE);
5542 glEnable(GL_SCISSOR_TEST);
5543 if (surface_is_offscreen(surface))
5544 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5546 glScissor(rect->x1, surface->currentDesc.Height - rect->y2,
5547 rect->x2 - rect->x1, rect->y2 - rect->y1);
5548 checkGLcall("glScissor");
5549 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5551 glDisable(GL_SCISSOR_TEST);
5553 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5555 glDisable(GL_BLEND);
5556 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
5558 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5559 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5560 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
5561 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
5562 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
5564 glClearColor(color[0], color[1], color[2], color[3]);
5565 glClear(GL_COLOR_BUFFER_BIT);
5566 checkGLcall("glClear");
5570 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
5572 context_release(context);
5575 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5576 IWineD3DSurface *pSurface, const WINED3DRECT *pRect, WINED3DCOLOR color)
5578 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5581 TRACE("iface %p, surface %p, rect %p, color 0x%08x.\n", iface, pSurface, pRect, color);
5583 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5584 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5585 return WINED3DERR_INVALIDCALL;
5588 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5589 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
5590 color_fill_fbo(iface, surface, pRect, c);
5593 /* Just forward this to the DirectDraw blitting engine */
5594 memset(&BltFx, 0, sizeof(BltFx));
5595 BltFx.dwSize = sizeof(BltFx);
5596 BltFx.u5.dwFillColor = color_convert_argb_to_fmt(color, surface->resource.format_desc->format);
5597 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
5598 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5602 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5603 IWineD3DRendertargetView *rendertarget_view, const float color[4])
5605 IWineD3DResource *resource;
5606 IWineD3DSurfaceImpl *surface;
5609 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5612 ERR("Failed to get resource, hr %#x\n", hr);
5616 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5618 FIXME("Only supported on surface resources\n");
5619 IWineD3DResource_Release(resource);
5623 surface = (IWineD3DSurfaceImpl *)resource;
5625 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5627 color_fill_fbo(iface, surface, NULL, color);
5634 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5636 c = ((DWORD)(color[2] * 255.0f));
5637 c |= ((DWORD)(color[1] * 255.0f)) << 8;
5638 c |= ((DWORD)(color[0] * 255.0f)) << 16;
5639 c |= ((DWORD)(color[3] * 255.0f)) << 24;
5641 /* Just forward this to the DirectDraw blitting engine */
5642 memset(&BltFx, 0, sizeof(BltFx));
5643 BltFx.dwSize = sizeof(BltFx);
5644 BltFx.u5.dwFillColor = color_convert_argb_to_fmt(c, surface->resource.format_desc->format);
5645 hr = IWineD3DSurface_Blt((IWineD3DSurface *)surface, NULL, NULL, NULL,
5646 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5649 ERR("Blt failed, hr %#x\n", hr);
5653 IWineD3DResource_Release(resource);
5656 /* rendertarget and depth stencil functions */
5657 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5658 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5660 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5662 ERR("(%p) : Only %d render targets are supported.\n",
5663 This, This->adapter->gl_info.limits.buffers);
5664 return WINED3DERR_INVALIDCALL;
5667 *ppRenderTarget = (IWineD3DSurface *)This->render_targets[RenderTargetIndex];
5668 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5669 /* Note inc ref on returned surface */
5670 if(*ppRenderTarget != NULL)
5671 IWineD3DSurface_AddRef(*ppRenderTarget);
5675 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5676 IWineD3DSurface *front, IWineD3DSurface *back)
5678 IWineD3DSurfaceImpl *front_impl = (IWineD3DSurfaceImpl *)front;
5679 IWineD3DSurfaceImpl *back_impl = (IWineD3DSurfaceImpl *)back;
5680 IWineD3DSwapChainImpl *swapchain;
5683 TRACE("iface %p, front %p, back %p.\n", iface, front, back);
5685 if (FAILED(hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&swapchain)))
5687 ERR("Failed to get the swapchain, hr %#x.\n", hr);
5691 if (front_impl && !(front_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5693 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5694 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5695 return WINED3DERR_INVALIDCALL;
5700 if (!(back_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5702 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5703 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5704 return WINED3DERR_INVALIDCALL;
5707 if (!swapchain->back_buffers)
5709 swapchain->back_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*swapchain->back_buffers));
5710 if (!swapchain->back_buffers)
5712 ERR("Failed to allocate back buffer array memory.\n");
5713 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5714 return E_OUTOFMEMORY;
5719 if (swapchain->front_buffer != front_impl)
5721 TRACE("Changing the front buffer from %p to %p.\n", swapchain->front_buffer, front_impl);
5723 if (swapchain->front_buffer)
5725 IWineD3DSurface_SetContainer((IWineD3DSurface *)swapchain->front_buffer, NULL);
5726 swapchain->front_buffer->Flags &= ~SFLAG_SWAPCHAIN;
5728 swapchain->front_buffer = front_impl;
5732 IWineD3DSurface_SetContainer(front, (IWineD3DBase *)swapchain);
5733 front_impl->Flags |= SFLAG_SWAPCHAIN;
5737 if (swapchain->back_buffers[0] != back_impl)
5739 TRACE("Changing the back buffer from %p to %p.\n", swapchain->back_buffers[0], back_impl);
5741 if (swapchain->back_buffers[0])
5743 IWineD3DSurface_SetContainer((IWineD3DSurface *)swapchain->back_buffers[0], NULL);
5744 swapchain->back_buffers[0]->Flags &= ~SFLAG_SWAPCHAIN;
5746 swapchain->back_buffers[0] = back_impl;
5750 swapchain->presentParms.BackBufferWidth = back_impl->currentDesc.Width;
5751 swapchain->presentParms.BackBufferHeight = back_impl->currentDesc.Height;
5752 swapchain->presentParms.BackBufferFormat = back_impl->resource.format_desc->format;
5753 swapchain->presentParms.BackBufferCount = 1;
5755 IWineD3DSurface_SetContainer(back, (IWineD3DBase *)swapchain);
5756 back_impl->Flags |= SFLAG_SWAPCHAIN;
5760 swapchain->presentParms.BackBufferCount = 0;
5761 HeapFree(GetProcessHeap(), 0, swapchain->back_buffers);
5762 swapchain->back_buffers = NULL;
5766 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5770 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5771 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5772 *ppZStencilSurface = (IWineD3DSurface *)This->depth_stencil;
5773 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5775 if(*ppZStencilSurface != NULL) {
5776 /* Note inc ref on returned surface */
5777 IWineD3DSurface_AddRef(*ppZStencilSurface);
5780 return WINED3DERR_NOTFOUND;
5784 void stretch_rect_fbo(IWineD3DDeviceImpl *device, IWineD3DSurfaceImpl *src_surface, const RECT *src_rect_in,
5785 IWineD3DSurfaceImpl *dst_surface, const RECT *dst_rect_in, const WINED3DTEXTUREFILTERTYPE filter)
5787 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5788 const struct wined3d_gl_info *gl_info;
5789 struct wined3d_context *context;
5791 POINT offset = {0, 0};
5792 RECT src_rect, dst_rect;
5794 TRACE("device %p, src_surface %p, src_rect_in %s, dst_surface %p, dst_rect_in %s, filter %s (0x%08x).\n",
5795 device, src_surface, wine_dbgstr_rect(src_rect_in), dst_surface,
5796 wine_dbgstr_rect(dst_rect_in), debug_d3dtexturefiltertype(filter), filter);
5798 src_rect = *src_rect_in;
5799 dst_rect = *dst_rect_in;
5802 case WINED3DTEXF_LINEAR:
5803 gl_filter = GL_LINEAR;
5807 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5808 case WINED3DTEXF_NONE:
5809 case WINED3DTEXF_POINT:
5810 gl_filter = GL_NEAREST;
5814 /* Make sure the drawables are up-to-date. Note that loading the
5815 * destination surface isn't strictly required if we overwrite the
5816 * entire surface. */
5817 IWineD3DSurface_LoadLocation((IWineD3DSurface *)src_surface, SFLAG_INDRAWABLE, NULL);
5818 IWineD3DSurface_LoadLocation((IWineD3DSurface *)dst_surface, SFLAG_INDRAWABLE, NULL);
5820 if (!surface_is_offscreen(src_surface)) context = context_acquire(device, src_surface, CTXUSAGE_RESOURCELOAD);
5821 else if (!surface_is_offscreen(dst_surface)) context = context_acquire(device, dst_surface, CTXUSAGE_RESOURCELOAD);
5822 else context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
5824 if (!context->valid)
5826 context_release(context);
5827 WARN("Invalid context, skipping blit.\n");
5831 gl_info = context->gl_info;
5833 if (!surface_is_offscreen(src_surface))
5835 GLenum buffer = surface_get_gl_buffer(src_surface);
5837 TRACE("Source surface %p is onscreen\n", src_surface);
5839 if(buffer == GL_FRONT) {
5842 ClientToScreen(context->win_handle, &offset);
5843 GetClientRect(context->win_handle, &windowsize);
5844 h = windowsize.bottom - windowsize.top;
5845 src_rect.left -= offset.x; src_rect.right -=offset.x;
5846 src_rect.top = offset.y + h - src_rect.top;
5847 src_rect.bottom = offset.y + h - src_rect.bottom;
5849 src_rect.top = src_surface->currentDesc.Height - src_rect.top;
5850 src_rect.bottom = src_surface->currentDesc.Height - src_rect.bottom;
5854 context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
5855 glReadBuffer(buffer);
5856 checkGLcall("glReadBuffer()");
5858 TRACE("Source surface %p is offscreen\n", src_surface);
5860 context_bind_fbo(context, GL_READ_FRAMEBUFFER, &context->src_fbo);
5861 context_attach_surface_fbo(context, GL_READ_FRAMEBUFFER, 0, src_surface);
5862 glReadBuffer(GL_COLOR_ATTACHMENT0);
5863 checkGLcall("glReadBuffer()");
5864 context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER, NULL, FALSE);
5868 /* Attach dst surface to dst fbo */
5869 if (!surface_is_offscreen(dst_surface))
5871 GLenum buffer = surface_get_gl_buffer(dst_surface);
5873 TRACE("Destination surface %p is onscreen\n", dst_surface);
5875 if(buffer == GL_FRONT) {
5878 ClientToScreen(context->win_handle, &offset);
5879 GetClientRect(context->win_handle, &windowsize);
5880 h = windowsize.bottom - windowsize.top;
5881 dst_rect.left -= offset.x; dst_rect.right -=offset.x;
5882 dst_rect.top = offset.y + h - dst_rect.top;
5883 dst_rect.bottom = offset.y + h - dst_rect.bottom;
5885 /* Screen coords = window coords, surface height = window height */
5886 dst_rect.top = dst_surface->currentDesc.Height - dst_rect.top;
5887 dst_rect.bottom = dst_surface->currentDesc.Height - dst_rect.bottom;
5891 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
5892 context_set_draw_buffer(context, buffer);
5896 TRACE("Destination surface %p is offscreen\n", dst_surface);
5899 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, &context->dst_fbo);
5900 context_attach_surface_fbo(context, GL_DRAW_FRAMEBUFFER, 0, dst_surface);
5901 context_set_draw_buffer(context, GL_COLOR_ATTACHMENT0);
5902 context_attach_depth_stencil_fbo(context, GL_DRAW_FRAMEBUFFER, NULL, FALSE);
5904 glDisable(GL_SCISSOR_TEST);
5905 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5907 gl_info->fbo_ops.glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom,
5908 dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom, mask, gl_filter);
5909 checkGLcall("glBlitFramebuffer()");
5913 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
5915 context_release(context);
5917 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)dst_surface, SFLAG_INDRAWABLE, TRUE);
5920 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget,
5921 BOOL set_viewport) {
5922 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5924 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5926 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5928 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
5929 This, RenderTargetIndex, This->adapter->gl_info.limits.buffers);
5930 return WINED3DERR_INVALIDCALL;
5933 /* MSDN says that null disables the render target
5934 but a device must always be associated with a render target
5935 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5937 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5938 FIXME("Trying to set render target 0 to NULL\n");
5939 return WINED3DERR_INVALIDCALL;
5941 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5942 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);
5943 return WINED3DERR_INVALIDCALL;
5946 /* If we are trying to set what we already have, don't bother */
5947 if (pRenderTarget == (IWineD3DSurface *)This->render_targets[RenderTargetIndex])
5949 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5953 IWineD3DSurface_AddRef(pRenderTarget);
5954 if (This->render_targets[RenderTargetIndex])
5955 IWineD3DSurface_Release((IWineD3DSurface *)This->render_targets[RenderTargetIndex]);
5956 This->render_targets[RenderTargetIndex] = (IWineD3DSurfaceImpl *)pRenderTarget;
5958 /* Render target 0 is special */
5959 if(RenderTargetIndex == 0 && set_viewport) {
5960 /* Finally, reset the viewport and scissor rect as the MSDN states.
5961 * Tests show that stateblock recording is ignored, the change goes
5962 * directly into the primary stateblock.
5964 This->stateBlock->viewport.Height = This->render_targets[0]->currentDesc.Height;
5965 This->stateBlock->viewport.Width = This->render_targets[0]->currentDesc.Width;
5966 This->stateBlock->viewport.X = 0;
5967 This->stateBlock->viewport.Y = 0;
5968 This->stateBlock->viewport.MaxZ = 1.0f;
5969 This->stateBlock->viewport.MinZ = 0.0f;
5970 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5972 This->stateBlock->scissorRect.top = 0;
5973 This->stateBlock->scissorRect.left = 0;
5974 This->stateBlock->scissorRect.right = This->stateBlock->viewport.Width;
5975 This->stateBlock->scissorRect.bottom = This->stateBlock->viewport.Height;
5976 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5981 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5982 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5983 IWineD3DSurfaceImpl *tmp;
5985 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, pNewZStencil, This->depth_stencil);
5987 if (This->depth_stencil == (IWineD3DSurfaceImpl *)pNewZStencil)
5989 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5993 if (This->depth_stencil)
5995 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5996 || This->depth_stencil->Flags & SFLAG_DISCARD)
5998 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5999 This->depth_stencil->currentDesc.Width,
6000 This->depth_stencil->currentDesc.Height);
6001 if (This->depth_stencil == This->onscreen_depth_stencil)
6003 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6004 This->onscreen_depth_stencil = NULL;
6009 tmp = This->depth_stencil;
6010 This->depth_stencil = (IWineD3DSurfaceImpl *)pNewZStencil;
6011 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
6012 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
6014 if ((!tmp && pNewZStencil) || (!pNewZStencil && tmp))
6016 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6017 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6018 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6019 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6025 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6026 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6027 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6028 /* TODO: the use of Impl is deprecated. */
6029 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6030 WINED3DLOCKED_RECT lockedRect;
6032 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6034 /* some basic validation checks */
6035 if(This->cursorTexture) {
6036 struct wined3d_context *context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6038 glDeleteTextures(1, &This->cursorTexture);
6040 context_release(context);
6041 This->cursorTexture = 0;
6044 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6045 This->haveHardwareCursor = TRUE;
6047 This->haveHardwareCursor = FALSE;
6050 WINED3DLOCKED_RECT rect;
6052 /* MSDN: Cursor must be A8R8G8B8 */
6053 if (pSur->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
6055 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6056 return WINED3DERR_INVALIDCALL;
6059 /* MSDN: Cursor must be smaller than the display mode */
6060 if(pSur->currentDesc.Width > This->ddraw_width ||
6061 pSur->currentDesc.Height > This->ddraw_height) {
6062 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);
6063 return WINED3DERR_INVALIDCALL;
6066 if (!This->haveHardwareCursor) {
6067 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6069 /* Do not store the surface's pointer because the application may
6070 * release it after setting the cursor image. Windows doesn't
6071 * addref the set surface, so we can't do this either without
6072 * creating circular refcount dependencies. Copy out the gl texture
6075 This->cursorWidth = pSur->currentDesc.Width;
6076 This->cursorHeight = pSur->currentDesc.Height;
6077 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6079 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
6080 const struct wined3d_format_desc *format_desc = getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, gl_info);
6081 struct wined3d_context *context;
6082 char *mem, *bits = rect.pBits;
6083 GLint intfmt = format_desc->glInternal;
6084 GLint format = format_desc->glFormat;
6085 GLint type = format_desc->glType;
6086 INT height = This->cursorHeight;
6087 INT width = This->cursorWidth;
6088 INT bpp = format_desc->byte_count;
6092 /* Reformat the texture memory (pitch and width can be
6094 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6095 for(i = 0; i < height; i++)
6096 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6097 IWineD3DSurface_UnlockRect(pCursorBitmap);
6099 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6103 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6105 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6106 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6109 /* Make sure that a proper texture unit is selected */
6110 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6111 checkGLcall("glActiveTextureARB");
6112 sampler = This->rev_tex_unit_map[0];
6113 if (sampler != WINED3D_UNMAPPED_STAGE)
6115 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6117 /* Create a new cursor texture */
6118 glGenTextures(1, &This->cursorTexture);
6119 checkGLcall("glGenTextures");
6120 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6121 checkGLcall("glBindTexture");
6122 /* Copy the bitmap memory into the cursor texture */
6123 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6124 HeapFree(GetProcessHeap(), 0, mem);
6125 checkGLcall("glTexImage2D");
6127 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6129 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6130 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6135 context_release(context);
6139 FIXME("A cursor texture was not returned.\n");
6140 This->cursorTexture = 0;
6145 /* Draw a hardware cursor */
6146 ICONINFO cursorInfo;
6148 /* Create and clear maskBits because it is not needed for
6149 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6151 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6152 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6153 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6154 WINED3DLOCK_NO_DIRTY_UPDATE |
6155 WINED3DLOCK_READONLY
6157 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6158 pSur->currentDesc.Height);
6160 cursorInfo.fIcon = FALSE;
6161 cursorInfo.xHotspot = XHotSpot;
6162 cursorInfo.yHotspot = YHotSpot;
6163 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6165 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6166 1, 32, lockedRect.pBits);
6167 IWineD3DSurface_UnlockRect(pCursorBitmap);
6168 /* Create our cursor and clean up. */
6169 cursor = CreateIconIndirect(&cursorInfo);
6171 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6172 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6173 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6174 This->hardwareCursor = cursor;
6175 HeapFree(GetProcessHeap(), 0, maskBits);
6179 This->xHotSpot = XHotSpot;
6180 This->yHotSpot = YHotSpot;
6184 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6185 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6186 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6188 This->xScreenSpace = XScreenSpace;
6189 This->yScreenSpace = YScreenSpace;
6195 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6196 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6197 BOOL oldVisible = This->bCursorVisible;
6200 TRACE("(%p) : visible(%d)\n", This, bShow);
6203 * When ShowCursor is first called it should make the cursor appear at the OS's last
6204 * known cursor position. Because of this, some applications just repetitively call
6205 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6208 This->xScreenSpace = pt.x;
6209 This->yScreenSpace = pt.y;
6211 if (This->haveHardwareCursor) {
6212 This->bCursorVisible = bShow;
6214 SetCursor(This->hardwareCursor);
6220 if (This->cursorTexture)
6221 This->bCursorVisible = bShow;
6227 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6228 TRACE("checking resource %p for eviction\n", resource);
6229 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6230 TRACE("Evicting %p\n", resource);
6231 IWineD3DResource_UnLoad(resource);
6233 IWineD3DResource_Release(resource);
6237 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6239 TRACE("iface %p.\n", iface);
6241 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6245 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6247 IWineD3DDeviceImpl *device = surface->resource.device;
6248 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6250 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6251 if(surface->Flags & SFLAG_DIBSECTION) {
6252 /* Release the DC */
6253 SelectObject(surface->hDC, surface->dib.holdbitmap);
6254 DeleteDC(surface->hDC);
6255 /* Release the DIB section */
6256 DeleteObject(surface->dib.DIBsection);
6257 surface->dib.bitmap_data = NULL;
6258 surface->resource.allocatedMemory = NULL;
6259 surface->Flags &= ~SFLAG_DIBSECTION;
6261 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6262 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6263 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6264 || gl_info->supported[WINE_NORMALIZED_TEXRECT])
6266 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6267 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6269 surface->pow2Width = surface->pow2Height = 1;
6270 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6271 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6274 if (surface->texture_name)
6276 struct wined3d_context *context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
6278 glDeleteTextures(1, &surface->texture_name);
6280 context_release(context);
6281 surface->texture_name = 0;
6282 surface->Flags &= ~SFLAG_CLIENT;
6284 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6285 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6286 surface->Flags |= SFLAG_NONPOW2;
6288 surface->Flags &= ~SFLAG_NONPOW2;
6290 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6291 surface->resource.allocatedMemory = NULL;
6292 surface->resource.heapMemory = NULL;
6293 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6295 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6297 if (!surface_init_sysmem(surface))
6299 return E_OUTOFMEMORY;
6304 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6305 TRACE("Unloading resource %p\n", resource);
6306 IWineD3DResource_UnLoad(resource);
6307 IWineD3DResource_Release(resource);
6311 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6314 WINED3DDISPLAYMODE m;
6317 /* All Windowed modes are supported, as is leaving the current mode */
6318 if(pp->Windowed) return TRUE;
6319 if(!pp->BackBufferWidth) return TRUE;
6320 if(!pp->BackBufferHeight) return TRUE;
6322 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6323 for(i = 0; i < count; i++) {
6324 memset(&m, 0, sizeof(m));
6325 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6327 ERR("EnumAdapterModes failed\n");
6329 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6330 /* Mode found, it is supported */
6334 /* Mode not found -> not supported */
6338 static void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6340 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6341 const struct wined3d_gl_info *gl_info;
6342 struct wined3d_context *context;
6343 IWineD3DBaseShaderImpl *shader;
6345 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6346 gl_info = context->gl_info;
6348 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6349 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6350 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6354 if(This->depth_blt_texture) {
6355 glDeleteTextures(1, &This->depth_blt_texture);
6356 This->depth_blt_texture = 0;
6358 if (This->depth_blt_rb) {
6359 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6360 This->depth_blt_rb = 0;
6361 This->depth_blt_rb_w = 0;
6362 This->depth_blt_rb_h = 0;
6366 This->blitter->free_private(iface);
6367 This->frag_pipe->free_private(iface);
6368 This->shader_backend->shader_free_private(iface);
6369 destroy_dummy_textures(This, gl_info);
6371 context_release(context);
6373 while (This->numContexts)
6375 context_destroy(This, This->contexts[0]);
6377 HeapFree(GetProcessHeap(), 0, swapchain->context);
6378 swapchain->context = NULL;
6379 swapchain->num_contexts = 0;
6382 static HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6384 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6385 struct wined3d_context *context;
6387 IWineD3DSurfaceImpl *target;
6389 /* Recreate the primary swapchain's context */
6390 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6391 if (!swapchain->context)
6393 ERR("Failed to allocate memory for swapchain context array.\n");
6394 return E_OUTOFMEMORY;
6397 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6398 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6400 WARN("Failed to create context.\n");
6401 HeapFree(GetProcessHeap(), 0, swapchain->context);
6405 swapchain->context[0] = context;
6406 swapchain->num_contexts = 1;
6407 create_dummy_textures(This);
6408 context_release(context);
6410 hr = This->shader_backend->shader_alloc_private(iface);
6413 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6417 hr = This->frag_pipe->alloc_private(iface);
6420 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6421 This->shader_backend->shader_free_private(iface);
6425 hr = This->blitter->alloc_private(iface);
6428 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6429 This->frag_pipe->free_private(iface);
6430 This->shader_backend->shader_free_private(iface);
6437 context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6438 destroy_dummy_textures(This, context->gl_info);
6439 context_release(context);
6440 context_destroy(This, context);
6441 HeapFree(GetProcessHeap(), 0, swapchain->context);
6442 swapchain->num_contexts = 0;
6446 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6447 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6448 IWineD3DSwapChainImpl *swapchain;
6450 BOOL DisplayModeChanged = FALSE;
6451 WINED3DDISPLAYMODE mode;
6452 TRACE("(%p)\n", This);
6454 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6456 ERR("Failed to get the first implicit swapchain\n");
6460 if(!is_display_mode_supported(This, pPresentationParameters)) {
6461 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6462 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6463 pPresentationParameters->BackBufferHeight);
6464 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6465 return WINED3DERR_INVALIDCALL;
6468 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6469 * on an existing gl context, so there's no real need for recreation.
6471 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6473 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6475 TRACE("New params:\n");
6476 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6477 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6478 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6479 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6480 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6481 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6482 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6483 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6484 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6485 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6486 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6487 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6488 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6490 /* No special treatment of these parameters. Just store them */
6491 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6492 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6493 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6494 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6496 /* What to do about these? */
6497 if(pPresentationParameters->BackBufferCount != 0 &&
6498 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6499 ERR("Cannot change the back buffer count yet\n");
6501 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6502 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6503 ERR("Cannot change the back buffer format yet\n");
6505 if(pPresentationParameters->hDeviceWindow != NULL &&
6506 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6507 ERR("Cannot change the device window yet\n");
6509 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6513 TRACE("Creating the depth stencil buffer\n");
6515 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6517 pPresentationParameters->BackBufferWidth,
6518 pPresentationParameters->BackBufferHeight,
6519 pPresentationParameters->AutoDepthStencilFormat,
6520 pPresentationParameters->MultiSampleType,
6521 pPresentationParameters->MultiSampleQuality,
6523 (IWineD3DSurface **)&This->auto_depth_stencil);
6526 ERR("Failed to create the depth stencil buffer\n");
6527 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6528 return WINED3DERR_INVALIDCALL;
6532 if (This->onscreen_depth_stencil)
6534 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6535 This->onscreen_depth_stencil = NULL;
6538 /* Reset the depth stencil */
6539 if (pPresentationParameters->EnableAutoDepthStencil)
6540 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6542 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6544 TRACE("Resetting stateblock\n");
6545 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6546 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6548 delete_opengl_contexts(iface, swapchain);
6550 if(pPresentationParameters->Windowed) {
6551 mode.Width = swapchain->orig_width;
6552 mode.Height = swapchain->orig_height;
6553 mode.RefreshRate = 0;
6554 mode.Format = swapchain->presentParms.BackBufferFormat;
6556 mode.Width = pPresentationParameters->BackBufferWidth;
6557 mode.Height = pPresentationParameters->BackBufferHeight;
6558 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6559 mode.Format = swapchain->presentParms.BackBufferFormat;
6562 /* Should Width == 800 && Height == 0 set 800x600? */
6563 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6564 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6565 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6569 if(!pPresentationParameters->Windowed) {
6570 DisplayModeChanged = TRUE;
6572 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6573 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6575 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6578 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6582 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6584 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6587 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6591 if (This->auto_depth_stencil)
6593 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6596 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6602 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6603 || DisplayModeChanged)
6605 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6607 if (!pPresentationParameters->Windowed)
6609 if(swapchain->presentParms.Windowed) {
6610 /* switch from windowed to fs */
6611 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6612 pPresentationParameters->BackBufferHeight);
6614 /* Fullscreen -> fullscreen mode change */
6615 MoveWindow(swapchain->device_window, 0, 0,
6616 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6620 else if (!swapchain->presentParms.Windowed)
6622 /* Fullscreen -> windowed switch */
6623 swapchain_restore_fullscreen_window(swapchain);
6625 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6626 } else if(!pPresentationParameters->Windowed) {
6627 DWORD style = This->style, exStyle = This->exStyle;
6628 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6629 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6630 * Reset to clear up their mess. Guild Wars also loses the device during that.
6634 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6635 pPresentationParameters->BackBufferHeight);
6636 This->style = style;
6637 This->exStyle = exStyle;
6640 /* Note: No parent needed for initial internal stateblock */
6641 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
6642 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6643 else TRACE("Created stateblock %p\n", This->stateBlock);
6644 This->updateStateBlock = This->stateBlock;
6645 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6647 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6649 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6652 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6655 GetClientRect(swapchain->win_handle, &client_rect);
6657 if(!swapchain->presentParms.BackBufferCount)
6659 TRACE("Single buffered rendering\n");
6660 swapchain->render_to_fbo = FALSE;
6662 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6663 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6665 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6666 swapchain->presentParms.BackBufferWidth,
6667 swapchain->presentParms.BackBufferHeight,
6668 client_rect.right, client_rect.bottom);
6669 swapchain->render_to_fbo = TRUE;
6673 TRACE("Rendering directly to GL_BACK\n");
6674 swapchain->render_to_fbo = FALSE;
6678 hr = create_primary_opengl_context(iface, swapchain);
6679 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6681 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6687 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6689 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6691 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6697 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6698 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6699 TRACE("(%p) : pParameters %p\n", This, pParameters);
6701 *pParameters = This->createParms;
6705 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6706 IWineD3DSwapChain *swapchain;
6708 TRACE("Relaying to swapchain\n");
6710 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6711 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6712 IWineD3DSwapChain_Release(swapchain);
6716 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6717 IWineD3DSwapChain *swapchain;
6719 TRACE("Relaying to swapchain\n");
6721 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6722 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6723 IWineD3DSwapChain_Release(swapchain);
6728 /** ********************************************************
6729 * Notification functions
6730 ** ********************************************************/
6731 /** This function must be called in the release of a resource when ref == 0,
6732 * the contents of resource must still be correct,
6733 * any handles to other resource held by the caller must be closed
6734 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6735 *****************************************************/
6736 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6738 TRACE("(%p) : Adding resource %p\n", This, resource);
6740 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6743 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6745 TRACE("(%p) : Removing resource %p\n", This, resource);
6747 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6750 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6752 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6755 TRACE("(%p) : resource %p\n", This, resource);
6757 context_resource_released((IWineD3DDevice *)This, resource, type);
6760 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6761 case WINED3DRTYPE_SURFACE: {
6764 if (This->d3d_initialized)
6766 for (i = 0; i < This->adapter->gl_info.limits.buffers; ++i)
6768 if (This->render_targets[i] == (IWineD3DSurfaceImpl *)resource)
6769 This->render_targets[i] = NULL;
6771 if (This->depth_stencil == (IWineD3DSurfaceImpl *)resource)
6772 This->depth_stencil = NULL;
6777 case WINED3DRTYPE_TEXTURE:
6778 case WINED3DRTYPE_CUBETEXTURE:
6779 case WINED3DRTYPE_VOLUMETEXTURE:
6780 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6781 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6782 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6783 This->stateBlock->textures[counter] = NULL;
6785 if (This->updateStateBlock != This->stateBlock ){
6786 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6787 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6788 This->updateStateBlock->textures[counter] = NULL;
6793 case WINED3DRTYPE_VOLUME:
6794 /* TODO: nothing really? */
6796 case WINED3DRTYPE_BUFFER:
6799 TRACE("Cleaning up stream pointers\n");
6801 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6802 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6803 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6805 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6806 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6807 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6808 This->updateStateBlock->streamSource[streamNumber] = 0;
6809 /* Set changed flag? */
6812 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) */
6813 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6814 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6815 This->stateBlock->streamSource[streamNumber] = 0;
6820 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6821 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6822 This->updateStateBlock->pIndexData = NULL;
6825 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6826 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6827 This->stateBlock->pIndexData = NULL;
6834 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6839 /* Remove the resource from the resourceStore */
6840 device_resource_remove(This, resource);
6842 TRACE("Resource released\n");
6846 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6847 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6848 IWineD3DResourceImpl *resource, *cursor;
6850 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6852 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6853 TRACE("enumerating resource %p\n", resource);
6854 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6855 ret = pCallback((IWineD3DResource *) resource, pData);
6856 if(ret == S_FALSE) {
6857 TRACE("Canceling enumeration\n");
6864 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6866 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6867 IWineD3DResourceImpl *resource;
6869 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6871 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6872 if (type == WINED3DRTYPE_SURFACE)
6874 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6876 TRACE("Found surface %p for dc %p.\n", resource, dc);
6877 *surface = (IWineD3DSurface *)resource;
6883 return WINED3DERR_INVALIDCALL;
6886 /**********************************************************
6887 * IWineD3DDevice VTbl follows
6888 **********************************************************/
6890 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6892 /*** IUnknown methods ***/
6893 IWineD3DDeviceImpl_QueryInterface,
6894 IWineD3DDeviceImpl_AddRef,
6895 IWineD3DDeviceImpl_Release,
6896 /*** IWineD3DDevice methods ***/
6897 IWineD3DDeviceImpl_GetParent,
6898 /*** Creation methods**/
6899 IWineD3DDeviceImpl_CreateBuffer,
6900 IWineD3DDeviceImpl_CreateVertexBuffer,
6901 IWineD3DDeviceImpl_CreateIndexBuffer,
6902 IWineD3DDeviceImpl_CreateStateBlock,
6903 IWineD3DDeviceImpl_CreateSurface,
6904 IWineD3DDeviceImpl_CreateRendertargetView,
6905 IWineD3DDeviceImpl_CreateTexture,
6906 IWineD3DDeviceImpl_CreateVolumeTexture,
6907 IWineD3DDeviceImpl_CreateVolume,
6908 IWineD3DDeviceImpl_CreateCubeTexture,
6909 IWineD3DDeviceImpl_CreateQuery,
6910 IWineD3DDeviceImpl_CreateSwapChain,
6911 IWineD3DDeviceImpl_CreateVertexDeclaration,
6912 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6913 IWineD3DDeviceImpl_CreateVertexShader,
6914 IWineD3DDeviceImpl_CreateGeometryShader,
6915 IWineD3DDeviceImpl_CreatePixelShader,
6916 IWineD3DDeviceImpl_CreatePalette,
6917 /*** Odd functions **/
6918 IWineD3DDeviceImpl_Init3D,
6919 IWineD3DDeviceImpl_InitGDI,
6920 IWineD3DDeviceImpl_Uninit3D,
6921 IWineD3DDeviceImpl_UninitGDI,
6922 IWineD3DDeviceImpl_SetMultithreaded,
6923 IWineD3DDeviceImpl_EvictManagedResources,
6924 IWineD3DDeviceImpl_GetAvailableTextureMem,
6925 IWineD3DDeviceImpl_GetBackBuffer,
6926 IWineD3DDeviceImpl_GetCreationParameters,
6927 IWineD3DDeviceImpl_GetDeviceCaps,
6928 IWineD3DDeviceImpl_GetDirect3D,
6929 IWineD3DDeviceImpl_GetDisplayMode,
6930 IWineD3DDeviceImpl_SetDisplayMode,
6931 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6932 IWineD3DDeviceImpl_GetRasterStatus,
6933 IWineD3DDeviceImpl_GetSwapChain,
6934 IWineD3DDeviceImpl_Reset,
6935 IWineD3DDeviceImpl_SetDialogBoxMode,
6936 IWineD3DDeviceImpl_SetCursorProperties,
6937 IWineD3DDeviceImpl_SetCursorPosition,
6938 IWineD3DDeviceImpl_ShowCursor,
6939 /*** Getters and setters **/
6940 IWineD3DDeviceImpl_SetClipPlane,
6941 IWineD3DDeviceImpl_GetClipPlane,
6942 IWineD3DDeviceImpl_SetClipStatus,
6943 IWineD3DDeviceImpl_GetClipStatus,
6944 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6945 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6946 IWineD3DDeviceImpl_SetDepthStencilSurface,
6947 IWineD3DDeviceImpl_GetDepthStencilSurface,
6948 IWineD3DDeviceImpl_SetGammaRamp,
6949 IWineD3DDeviceImpl_GetGammaRamp,
6950 IWineD3DDeviceImpl_SetIndexBuffer,
6951 IWineD3DDeviceImpl_GetIndexBuffer,
6952 IWineD3DDeviceImpl_SetBaseVertexIndex,
6953 IWineD3DDeviceImpl_GetBaseVertexIndex,
6954 IWineD3DDeviceImpl_SetLight,
6955 IWineD3DDeviceImpl_GetLight,
6956 IWineD3DDeviceImpl_SetLightEnable,
6957 IWineD3DDeviceImpl_GetLightEnable,
6958 IWineD3DDeviceImpl_SetMaterial,
6959 IWineD3DDeviceImpl_GetMaterial,
6960 IWineD3DDeviceImpl_SetNPatchMode,
6961 IWineD3DDeviceImpl_GetNPatchMode,
6962 IWineD3DDeviceImpl_SetPaletteEntries,
6963 IWineD3DDeviceImpl_GetPaletteEntries,
6964 IWineD3DDeviceImpl_SetPixelShader,
6965 IWineD3DDeviceImpl_GetPixelShader,
6966 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6967 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6968 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6969 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6970 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6971 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6972 IWineD3DDeviceImpl_SetRenderState,
6973 IWineD3DDeviceImpl_GetRenderState,
6974 IWineD3DDeviceImpl_SetRenderTarget,
6975 IWineD3DDeviceImpl_GetRenderTarget,
6976 IWineD3DDeviceImpl_SetFrontBackBuffers,
6977 IWineD3DDeviceImpl_SetSamplerState,
6978 IWineD3DDeviceImpl_GetSamplerState,
6979 IWineD3DDeviceImpl_SetScissorRect,
6980 IWineD3DDeviceImpl_GetScissorRect,
6981 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6982 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6983 IWineD3DDeviceImpl_SetStreamSource,
6984 IWineD3DDeviceImpl_GetStreamSource,
6985 IWineD3DDeviceImpl_SetStreamSourceFreq,
6986 IWineD3DDeviceImpl_GetStreamSourceFreq,
6987 IWineD3DDeviceImpl_SetTexture,
6988 IWineD3DDeviceImpl_GetTexture,
6989 IWineD3DDeviceImpl_SetTextureStageState,
6990 IWineD3DDeviceImpl_GetTextureStageState,
6991 IWineD3DDeviceImpl_SetTransform,
6992 IWineD3DDeviceImpl_GetTransform,
6993 IWineD3DDeviceImpl_SetVertexDeclaration,
6994 IWineD3DDeviceImpl_GetVertexDeclaration,
6995 IWineD3DDeviceImpl_SetVertexShader,
6996 IWineD3DDeviceImpl_GetVertexShader,
6997 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6998 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6999 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7000 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7001 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7002 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7003 IWineD3DDeviceImpl_SetViewport,
7004 IWineD3DDeviceImpl_GetViewport,
7005 IWineD3DDeviceImpl_MultiplyTransform,
7006 IWineD3DDeviceImpl_ValidateDevice,
7007 IWineD3DDeviceImpl_ProcessVertices,
7008 /*** State block ***/
7009 IWineD3DDeviceImpl_BeginStateBlock,
7010 IWineD3DDeviceImpl_EndStateBlock,
7011 /*** Scene management ***/
7012 IWineD3DDeviceImpl_BeginScene,
7013 IWineD3DDeviceImpl_EndScene,
7014 IWineD3DDeviceImpl_Present,
7015 IWineD3DDeviceImpl_Clear,
7016 IWineD3DDeviceImpl_ClearRendertargetView,
7018 IWineD3DDeviceImpl_SetPrimitiveType,
7019 IWineD3DDeviceImpl_GetPrimitiveType,
7020 IWineD3DDeviceImpl_DrawPrimitive,
7021 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7022 IWineD3DDeviceImpl_DrawPrimitiveUP,
7023 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7024 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7025 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7026 IWineD3DDeviceImpl_DrawRectPatch,
7027 IWineD3DDeviceImpl_DrawTriPatch,
7028 IWineD3DDeviceImpl_DeletePatch,
7029 IWineD3DDeviceImpl_ColorFill,
7030 IWineD3DDeviceImpl_UpdateTexture,
7031 IWineD3DDeviceImpl_UpdateSurface,
7032 IWineD3DDeviceImpl_GetFrontBufferData,
7033 /*** object tracking ***/
7034 IWineD3DDeviceImpl_EnumResources,
7035 IWineD3DDeviceImpl_GetSurfaceFromDC,
7036 IWineD3DDeviceImpl_AcquireFocusWindow,
7037 IWineD3DDeviceImpl_ReleaseFocusWindow,
7040 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
7041 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
7042 IUnknown *parent, IWineD3DDeviceParent *device_parent)
7044 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
7045 const struct fragment_pipeline *fragment_pipeline;
7046 struct shader_caps shader_caps;
7047 struct fragment_caps ffp_caps;
7048 WINED3DDISPLAYMODE mode;
7052 device->lpVtbl = &IWineD3DDevice_Vtbl;
7054 device->wined3d = (IWineD3D *)wined3d;
7055 IWineD3D_AddRef(device->wined3d);
7056 device->adapter = wined3d->adapter_count ? adapter : NULL;
7057 device->parent = parent;
7058 device->device_parent = device_parent;
7059 list_init(&device->resources);
7060 list_init(&device->shaders);
7062 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
7063 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
7065 /* Get the initial screen setup for ddraw. */
7066 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
7069 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
7070 IWineD3D_Release(device->wined3d);
7073 device->ddraw_width = mode.Width;
7074 device->ddraw_height = mode.Height;
7075 device->ddraw_format = mode.Format;
7077 /* Save the creation parameters. */
7078 device->createParms.AdapterOrdinal = adapter_idx;
7079 device->createParms.DeviceType = device_type;
7080 device->createParms.hFocusWindow = focus_window;
7081 device->createParms.BehaviorFlags = flags;
7083 device->devType = device_type;
7084 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
7086 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
7087 device->shader_backend = adapter->shader_backend;
7089 memset(&shader_caps, 0, sizeof(shader_caps));
7090 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
7091 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
7092 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
7093 device->vs_clipping = shader_caps.VSClipping;
7095 memset(&ffp_caps, 0, sizeof(ffp_caps));
7096 fragment_pipeline = adapter->fragment_pipe;
7097 device->frag_pipe = fragment_pipeline;
7098 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
7099 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
7101 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
7102 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
7105 ERR("Failed to compile state table, hr %#x.\n", hr);
7106 IWineD3D_Release(device->wined3d);
7110 device->blitter = adapter->blitter;
7116 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7117 DWORD rep = This->StateTable[state].representative;
7118 struct wined3d_context *context;
7123 for(i = 0; i < This->numContexts; i++) {
7124 context = This->contexts[i];
7125 if(isStateDirty(context, rep)) continue;
7127 context->dirtyArray[context->numDirtyEntries++] = rep;
7128 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
7129 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
7130 context->isStateDirty[idx] |= (1 << shift);
7134 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7136 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7137 *width = context->current_rt->pow2Width;
7138 *height = context->current_rt->pow2Height;
7141 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7143 IWineD3DSwapChainImpl *swapchain = context->swapchain;
7144 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7145 * current context's drawable, which is the size of the back buffer of the swapchain
7146 * the active context belongs to. */
7147 *width = swapchain->presentParms.BackBufferWidth;
7148 *height = swapchain->presentParms.BackBufferHeight;
7151 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
7152 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
7154 if (device->filter_messages)
7156 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7157 window, message, wparam, lparam);
7158 return DefWindowProcW(window, message, wparam, lparam);
7161 if (message == WM_DESTROY)
7163 TRACE("unregister window %p.\n", window);
7164 wined3d_unregister_window(window);
7166 if (device->focus_window == window) device->focus_window = NULL;
7167 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7170 return CallWindowProcW(proc, window, message, wparam, lparam);