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);
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0f, 1.0f, 1.0f, 0.0f }, /* Diffuse r,g,b,a */
43 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Specular r,g,b,a */
44 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Ambient r,g,b,a, */
45 { 0.0f, 0.0f, 0.0f }, /* Position x,y,z */
46 { 0.0f, 0.0f, 1.0f }, /* Direction x,y,z */
49 0.0f, 0.0f, 0.0f, /* Attenuation 0,1,2 */
54 /**********************************************************
55 * Global variable / Constants follow
56 **********************************************************/
57 const float identity[] =
59 1.0f, 0.0f, 0.0f, 0.0f,
60 0.0f, 1.0f, 0.0f, 0.0f,
61 0.0f, 0.0f, 1.0f, 0.0f,
62 0.0f, 0.0f, 0.0f, 1.0f,
63 }; /* When needed for comparisons */
65 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
66 * actually have the same values in GL and D3D. */
67 static GLenum gl_primitive_type_from_d3d(WINED3DPRIMITIVETYPE primitive_type)
69 switch(primitive_type)
71 case WINED3DPT_POINTLIST:
74 case WINED3DPT_LINELIST:
77 case WINED3DPT_LINESTRIP:
80 case WINED3DPT_TRIANGLELIST:
83 case WINED3DPT_TRIANGLESTRIP:
84 return GL_TRIANGLE_STRIP;
86 case WINED3DPT_TRIANGLEFAN:
87 return GL_TRIANGLE_FAN;
89 case WINED3DPT_LINELIST_ADJ:
90 return GL_LINES_ADJACENCY_ARB;
92 case WINED3DPT_LINESTRIP_ADJ:
93 return GL_LINE_STRIP_ADJACENCY_ARB;
95 case WINED3DPT_TRIANGLELIST_ADJ:
96 return GL_TRIANGLES_ADJACENCY_ARB;
98 case WINED3DPT_TRIANGLESTRIP_ADJ:
99 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
102 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
107 static WINED3DPRIMITIVETYPE d3d_primitive_type_from_gl(GLenum primitive_type)
109 switch(primitive_type)
112 return WINED3DPT_POINTLIST;
115 return WINED3DPT_LINELIST;
118 return WINED3DPT_LINESTRIP;
121 return WINED3DPT_TRIANGLELIST;
123 case GL_TRIANGLE_STRIP:
124 return WINED3DPT_TRIANGLESTRIP;
126 case GL_TRIANGLE_FAN:
127 return WINED3DPT_TRIANGLEFAN;
129 case GL_LINES_ADJACENCY_ARB:
130 return WINED3DPT_LINELIST_ADJ;
132 case GL_LINE_STRIP_ADJACENCY_ARB:
133 return WINED3DPT_LINESTRIP_ADJ;
135 case GL_TRIANGLES_ADJACENCY_ARB:
136 return WINED3DPT_TRIANGLELIST_ADJ;
138 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
139 return WINED3DPT_TRIANGLESTRIP_ADJ;
142 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
143 return WINED3DPT_UNDEFINED;
147 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
149 if ((usage == WINED3DDECLUSAGE_POSITION || usage == WINED3DDECLUSAGE_POSITIONT) && usage_idx == 0)
150 *regnum = WINED3D_FFP_POSITION;
151 else if (usage == WINED3DDECLUSAGE_BLENDWEIGHT && usage_idx == 0)
152 *regnum = WINED3D_FFP_BLENDWEIGHT;
153 else if (usage == WINED3DDECLUSAGE_BLENDINDICES && usage_idx == 0)
154 *regnum = WINED3D_FFP_BLENDINDICES;
155 else if (usage == WINED3DDECLUSAGE_NORMAL && usage_idx == 0)
156 *regnum = WINED3D_FFP_NORMAL;
157 else if (usage == WINED3DDECLUSAGE_PSIZE && usage_idx == 0)
158 *regnum = WINED3D_FFP_PSIZE;
159 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 0)
160 *regnum = WINED3D_FFP_DIFFUSE;
161 else if (usage == WINED3DDECLUSAGE_COLOR && usage_idx == 1)
162 *regnum = WINED3D_FFP_SPECULAR;
163 else if (usage == WINED3DDECLUSAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
164 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
167 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
175 /* Context activation is done by the caller. */
176 void device_stream_info_from_declaration(IWineD3DDeviceImpl *This,
177 BOOL use_vshader, struct wined3d_stream_info *stream_info, BOOL *fixup)
179 /* We need to deal with frequency data! */
180 IWineD3DVertexDeclarationImpl *declaration = (IWineD3DVertexDeclarationImpl *)This->stateBlock->vertexDecl;
183 stream_info->use_map = 0;
184 stream_info->swizzle_map = 0;
186 /* Check for transformed vertices, disable vertex shader if present. */
187 stream_info->position_transformed = declaration->position_transformed;
188 if (declaration->position_transformed) use_vshader = FALSE;
190 /* Translate the declaration into strided data. */
191 for (i = 0; i < declaration->element_count; ++i)
193 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
194 GLuint buffer_object = 0;
195 const BYTE *data = NULL;
200 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
201 element, i + 1, declaration->element_count);
203 if (!This->stateBlock->streamSource[element->input_slot]) continue;
205 stride = This->stateBlock->streamStride[element->input_slot];
206 if (This->stateBlock->streamIsUP)
208 TRACE("Stream %u is UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
210 data = (BYTE *)This->stateBlock->streamSource[element->input_slot];
214 TRACE("Stream %u isn't UP, %p\n", element->input_slot, This->stateBlock->streamSource[element->input_slot]);
215 data = buffer_get_memory(This->stateBlock->streamSource[element->input_slot],
216 &This->adapter->gl_info, &buffer_object);
218 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
219 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
220 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
221 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
222 * not, drawStridedSlow is needed, including a vertex buffer path. */
223 if (This->stateBlock->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 &This->adapter->gl_info);
229 if ((UINT_PTR)data < -This->stateBlock->loadBaseVertexIndex * stride)
231 FIXME("System memory vertex data load offset is negative!\n");
237 if (buffer_object) *fixup = TRUE;
238 else if (*fixup && !use_vshader
239 && (element->usage == WINED3DDECLUSAGE_COLOR
240 || element->usage == WINED3DDECLUSAGE_POSITIONT))
242 static BOOL warned = FALSE;
245 /* This may be bad with the fixed function pipeline. */
246 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
252 data += element->offset;
254 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
258 if (element->output_slot == ~0U)
260 /* TODO: Assuming vertexdeclarations are usually used with the
261 * same or a similar shader, it might be worth it to store the
262 * last used output slot and try that one first. */
263 stride_used = vshader_get_input(This->stateBlock->vertexShader,
264 element->usage, element->usage_idx, &idx);
268 idx = element->output_slot;
274 if (!element->ffp_valid)
276 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
277 debug_d3dformat(element->format_desc->id), debug_d3ddeclusage(element->usage));
282 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
288 TRACE("Load %s array %u [usage %s, usage_idx %u, "
289 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
290 use_vshader ? "shader": "fixed function", idx,
291 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
292 element->offset, stride, debug_d3dformat(element->format_desc->id), buffer_object);
294 stream_info->elements[idx].format_desc = element->format_desc;
295 stream_info->elements[idx].stride = stride;
296 stream_info->elements[idx].data = data;
297 stream_info->elements[idx].stream_idx = element->input_slot;
298 stream_info->elements[idx].buffer_object = buffer_object;
300 if (!This->adapter->gl_info.supported[ARB_VERTEX_ARRAY_BGRA]
301 && element->format_desc->id == WINED3DFMT_B8G8R8A8_UNORM)
303 stream_info->swizzle_map |= 1 << idx;
305 stream_info->use_map |= 1 << idx;
309 This->num_buffer_queries = 0;
310 if (!This->stateBlock->streamIsUP)
312 WORD map = stream_info->use_map;
314 /* PreLoad all the vertex buffers. */
315 for (i = 0; map; map >>= 1, ++i)
317 struct wined3d_stream_info_element *element;
318 struct wined3d_buffer *buffer;
319 struct wined3d_event_query *query;
321 if (!(map & 1)) continue;
323 element = &stream_info->elements[i];
324 buffer = (struct wined3d_buffer *)This->stateBlock->streamSource[element->stream_idx];
325 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)buffer);
327 /* If PreLoad dropped the buffer object, update the stream info. */
328 if (buffer->buffer_object != element->buffer_object)
330 element->buffer_object = 0;
331 element->data = buffer_get_sysmem(buffer, &This->adapter->gl_info) + (ptrdiff_t)element->data;
334 query = ((struct wined3d_buffer *) buffer)->query;
337 This->buffer_queries[This->num_buffer_queries++] = query;
343 static void stream_info_element_from_strided(const struct wined3d_gl_info *gl_info,
344 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
346 const struct wined3d_format_desc *format_desc = getFormatDescEntry(strided->format, gl_info);
347 e->format_desc = format_desc;
348 e->stride = strided->dwStride;
349 e->data = strided->lpData;
351 e->buffer_object = 0;
354 static void device_stream_info_from_strided(const struct wined3d_gl_info *gl_info,
355 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
359 memset(stream_info, 0, sizeof(*stream_info));
361 if (strided->position.lpData)
362 stream_info_element_from_strided(gl_info, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
363 if (strided->normal.lpData)
364 stream_info_element_from_strided(gl_info, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
365 if (strided->diffuse.lpData)
366 stream_info_element_from_strided(gl_info, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
367 if (strided->specular.lpData)
368 stream_info_element_from_strided(gl_info, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
370 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
372 if (strided->texCoords[i].lpData)
373 stream_info_element_from_strided(gl_info, &strided->texCoords[i],
374 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
377 stream_info->position_transformed = strided->position_transformed;
379 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
381 if (!stream_info->elements[i].format_desc) continue;
383 if (!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
384 && stream_info->elements[i].format_desc->id == WINED3DFMT_B8G8R8A8_UNORM)
386 stream_info->swizzle_map |= 1 << i;
388 stream_info->use_map |= 1 << i;
392 static void device_trace_strided_stream_info(const struct wined3d_stream_info *stream_info)
394 TRACE("Strided Data:\n");
395 TRACE_STRIDED(stream_info, WINED3D_FFP_POSITION);
396 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDWEIGHT);
397 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDINDICES);
398 TRACE_STRIDED(stream_info, WINED3D_FFP_NORMAL);
399 TRACE_STRIDED(stream_info, WINED3D_FFP_PSIZE);
400 TRACE_STRIDED(stream_info, WINED3D_FFP_DIFFUSE);
401 TRACE_STRIDED(stream_info, WINED3D_FFP_SPECULAR);
402 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD0);
403 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD1);
404 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD2);
405 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD3);
406 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD4);
407 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD5);
408 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD6);
409 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD7);
412 /* Context activation is done by the caller. */
413 void device_update_stream_info(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
415 struct wined3d_stream_info *stream_info = &device->strided_streams;
416 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
417 BOOL vs = stateblock->vertexShader && device->vs_selected_mode != SHADER_NONE;
420 if (device->up_strided)
422 /* Note: this is a ddraw fixed-function code path. */
423 TRACE("=============================== Strided Input ================================\n");
424 device_stream_info_from_strided(gl_info, device->up_strided, stream_info);
425 if (TRACE_ON(d3d)) device_trace_strided_stream_info(stream_info);
429 TRACE("============================= Vertex Declaration =============================\n");
430 device_stream_info_from_declaration(device, vs, stream_info, &fixup);
433 if (vs && !stream_info->position_transformed)
435 if (((IWineD3DVertexDeclarationImpl *)stateblock->vertexDecl)->half_float_conv_needed && !fixup)
437 TRACE("Using drawStridedSlow with vertex shaders for FLOAT16 conversion.\n");
438 device->useDrawStridedSlow = TRUE;
442 device->useDrawStridedSlow = FALSE;
447 WORD slow_mask = (1 << WINED3D_FFP_PSIZE);
448 slow_mask |= -!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
449 & ((1 << WINED3D_FFP_DIFFUSE) | (1 << WINED3D_FFP_SPECULAR));
451 if ((stream_info->position_transformed || (stream_info->use_map & slow_mask)) && !fixup)
453 device->useDrawStridedSlow = TRUE;
457 device->useDrawStridedSlow = FALSE;
462 static void device_preload_texture(IWineD3DStateBlockImpl *stateblock, unsigned int idx)
464 IWineD3DBaseTextureImpl *texture;
465 enum WINED3DSRGB srgb;
467 if (!(texture = (IWineD3DBaseTextureImpl *)stateblock->textures[idx])) return;
468 srgb = stateblock->samplerState[idx][WINED3DSAMP_SRGBTEXTURE] ? SRGB_SRGB : SRGB_RGB;
469 texture->baseTexture.internal_preload((IWineD3DBaseTexture *)texture, srgb);
472 void device_preload_textures(IWineD3DDeviceImpl *device)
474 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
477 if (use_vs(stateblock))
479 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i)
481 if (((IWineD3DBaseShaderImpl *)stateblock->vertexShader)->baseShader.reg_maps.sampler_type[i])
482 device_preload_texture(stateblock, MAX_FRAGMENT_SAMPLERS + i);
486 if (use_ps(stateblock))
488 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
490 if (((IWineD3DBaseShaderImpl *)stateblock->pixelShader)->baseShader.reg_maps.sampler_type[i])
491 device_preload_texture(stateblock, i);
496 WORD ffu_map = device->fixed_function_usage_map;
498 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
501 device_preload_texture(stateblock, i);
506 BOOL device_context_add(IWineD3DDeviceImpl *device, struct wined3d_context *context)
508 struct wined3d_context **new_array;
510 TRACE("Adding context %p.\n", context);
512 if (!device->contexts) new_array = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_array));
513 else new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, sizeof(*new_array) * (device->numContexts + 1));
517 ERR("Failed to grow the context array.\n");
521 new_array[device->numContexts++] = context;
522 device->contexts = new_array;
526 void device_context_remove(IWineD3DDeviceImpl *device, struct wined3d_context *context)
528 struct wined3d_context **new_array;
532 TRACE("Removing context %p.\n", context);
534 for (i = 0; i < device->numContexts; ++i)
536 if (device->contexts[i] == context)
545 ERR("Context %p doesn't exist in context array.\n", context);
549 if (!--device->numContexts)
551 HeapFree(GetProcessHeap(), 0, device->contexts);
552 device->contexts = NULL;
556 memmove(&device->contexts[i], &device->contexts[i + 1], (device->numContexts - i) * sizeof(*device->contexts));
557 new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, device->numContexts * sizeof(*device->contexts));
560 ERR("Failed to shrink context array. Oh well.\n");
564 device->contexts = new_array;
567 void device_get_draw_rect(IWineD3DDeviceImpl *device, RECT *rect)
569 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
570 WINED3DVIEWPORT *vp = &stateblock->viewport;
572 SetRect(rect, vp->X, vp->Y, vp->X + vp->Width, vp->Y + vp->Height);
574 if (stateblock->renderState[WINED3DRS_SCISSORTESTENABLE])
576 IntersectRect(rect, rect, &stateblock->scissorRect);
580 void device_switch_onscreen_ds(IWineD3DDeviceImpl *device,
581 struct wined3d_context *context, IWineD3DSurfaceImpl *depth_stencil)
583 if (device->onscreen_depth_stencil)
585 surface_load_ds_location(device->onscreen_depth_stencil, context, SFLAG_DS_OFFSCREEN);
586 surface_modify_ds_location(device->onscreen_depth_stencil, SFLAG_DS_OFFSCREEN,
587 device->onscreen_depth_stencil->ds_current_size.cx,
588 device->onscreen_depth_stencil->ds_current_size.cy);
589 IWineD3DSurface_Release((IWineD3DSurface *)device->onscreen_depth_stencil);
591 device->onscreen_depth_stencil = depth_stencil;
592 IWineD3DSurface_AddRef((IWineD3DSurface *)device->onscreen_depth_stencil);
595 static BOOL is_full_clear(IWineD3DSurfaceImpl *target, const RECT *draw_rect, const RECT *clear_rect)
597 /* partial draw rect */
598 if (draw_rect->left || draw_rect->top
599 || draw_rect->right < target->currentDesc.Width
600 || draw_rect->bottom < target->currentDesc.Height)
603 /* partial clear rect */
604 if (clear_rect && (clear_rect->left > 0 || clear_rect->top > 0
605 || clear_rect->right < target->currentDesc.Width
606 || clear_rect->bottom < target->currentDesc.Height))
612 static void prepare_ds_clear(IWineD3DSurfaceImpl *ds, struct wined3d_context *context,
613 DWORD location, const RECT *draw_rect, UINT rect_count, const RECT *clear_rect)
615 RECT current_rect, r;
617 if (ds->Flags & location)
618 SetRect(¤t_rect, 0, 0,
619 ds->ds_current_size.cx,
620 ds->ds_current_size.cy);
622 SetRectEmpty(¤t_rect);
624 IntersectRect(&r, draw_rect, ¤t_rect);
625 if (EqualRect(&r, draw_rect))
627 /* current_rect ⊇ draw_rect, modify only. */
628 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
632 if (EqualRect(&r, ¤t_rect))
634 /* draw_rect ⊇ current_rect, test if we're doing a full clear. */
638 /* Full clear, modify only. */
639 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
643 IntersectRect(&r, draw_rect, clear_rect);
644 if (EqualRect(&r, draw_rect))
646 /* clear_rect ⊇ draw_rect, modify only. */
647 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
653 surface_load_ds_location(ds, context, location);
654 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
657 HRESULT device_clear_render_targets(IWineD3DDeviceImpl *device, UINT rt_count, IWineD3DSurfaceImpl **rts,
658 UINT rect_count, const RECT *rects, const RECT *draw_rect, DWORD flags,
659 const WINED3DCOLORVALUE *color, float depth, DWORD stencil)
661 const RECT *clear_rect = (rect_count > 0 && rects) ? (const RECT *)rects : NULL;
662 IWineD3DSurfaceImpl *depth_stencil = device->depth_stencil;
663 IWineD3DSurfaceImpl *target = rts[0];
664 UINT drawable_width, drawable_height;
665 struct wined3d_context *context;
666 GLbitfield clear_mask = 0;
669 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
670 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
671 * for the cleared parts, and the untouched parts.
673 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
674 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
675 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
676 * checking all this if the dest surface is in the drawable anyway. */
677 if (flags & WINED3DCLEAR_TARGET && !is_full_clear(target, draw_rect, clear_rect))
679 for (i = 0; i < rt_count; ++i)
681 if (rts[i]) surface_load_location(rts[i], SFLAG_INDRAWABLE, NULL);
685 context = context_acquire(device, target);
688 context_release(context);
689 WARN("Invalid context, skipping clear.\n");
693 context_apply_clear_state(context, device, rt_count, rts, depth_stencil);
695 target->get_drawable_size(context, &drawable_width, &drawable_height);
699 /* Only set the values up once, as they are not changing. */
700 if (flags & WINED3DCLEAR_STENCIL)
702 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
704 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
705 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE));
708 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
709 glClearStencil(stencil);
710 checkGLcall("glClearStencil");
711 clear_mask = clear_mask | GL_STENCIL_BUFFER_BIT;
714 if (flags & WINED3DCLEAR_ZBUFFER)
716 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
718 if (location == SFLAG_DS_ONSCREEN && depth_stencil != device->onscreen_depth_stencil)
719 device_switch_onscreen_ds(device, context, depth_stencil);
720 prepare_ds_clear(depth_stencil, context, location, draw_rect, rect_count, clear_rect);
721 surface_modify_location(depth_stencil, SFLAG_INDRAWABLE, TRUE);
723 glDepthMask(GL_TRUE);
724 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
726 checkGLcall("glClearDepth");
727 clear_mask = clear_mask | GL_DEPTH_BUFFER_BIT;
730 if (flags & WINED3DCLEAR_TARGET)
732 for (i = 0; i < rt_count; ++i)
734 if (rts[i]) surface_modify_location(rts[i], SFLAG_INDRAWABLE, TRUE);
737 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
738 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
739 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
740 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
741 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
742 glClearColor(color->r, color->g, color->b, color->a);
743 checkGLcall("glClearColor");
744 clear_mask = clear_mask | GL_COLOR_BUFFER_BIT;
749 if (context->render_offscreen)
751 glScissor(draw_rect->left, draw_rect->top,
752 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
756 glScissor(draw_rect->left, drawable_height - draw_rect->bottom,
757 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
759 checkGLcall("glScissor");
761 checkGLcall("glClear");
767 /* Now process each rect in turn. */
768 for (i = 0; i < rect_count; ++i)
770 /* Note that GL uses lower left, width/height. */
771 IntersectRect(¤t_rect, draw_rect, &clear_rect[i]);
773 TRACE("clear_rect[%u] %s, current_rect %s.\n", i,
774 wine_dbgstr_rect(&clear_rect[i]),
775 wine_dbgstr_rect(¤t_rect));
777 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
778 * The rectangle is not cleared, no error is returned, but further rectanlges are
779 * still cleared if they are valid. */
780 if (current_rect.left > current_rect.right || current_rect.top > current_rect.bottom)
782 TRACE("Rectangle with negative dimensions, ignoring.\n");
786 if (context->render_offscreen)
788 glScissor(current_rect.left, current_rect.top,
789 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
793 glScissor(current_rect.left, drawable_height - current_rect.bottom,
794 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
796 checkGLcall("glScissor");
799 checkGLcall("glClear");
805 if (wined3d_settings.strict_draw_ordering || (target->container.type == WINED3D_CONTAINER_SWAPCHAIN
806 && target->container.u.swapchain->front_buffer == target))
807 wglFlush(); /* Flush to ensure ordering across contexts. */
809 context_release(context);
815 /**********************************************************
816 * IUnknown parts follows
817 **********************************************************/
819 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
821 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
823 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
824 if (IsEqualGUID(riid, &IID_IUnknown)
825 || IsEqualGUID(riid, &IID_IWineD3DBase)
826 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
827 IUnknown_AddRef(iface);
832 return E_NOINTERFACE;
835 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
836 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
837 ULONG refCount = InterlockedIncrement(&This->ref);
839 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
843 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
844 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
845 ULONG refCount = InterlockedDecrement(&This->ref);
847 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
852 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
853 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
854 This->multistate_funcs[i] = NULL;
857 /* TODO: Clean up all the surfaces and textures! */
858 /* NOTE: You must release the parent if the object was created via a callback
859 ** ***************************/
861 if (!list_empty(&This->resources))
863 IWineD3DResourceImpl *resource;
864 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
866 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
868 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
869 FIXME("Leftover resource %p with type %s (%#x).\n",
870 resource, debug_d3dresourcetype(type), type);
874 if(This->contexts) ERR("Context array not freed!\n");
875 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
876 This->haveHardwareCursor = FALSE;
878 IWineD3D_Release(This->wined3d);
879 This->wined3d = NULL;
880 HeapFree(GetProcessHeap(), 0, This);
881 TRACE("Freed device %p\n", This);
887 /**********************************************************
888 * IWineD3DDevice implementation follows
889 **********************************************************/
890 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
891 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
892 *pParent = This->parent;
893 IUnknown_AddRef(This->parent);
897 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
898 const void *data, IUnknown *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
900 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
901 struct wined3d_buffer *object;
904 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
906 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
909 ERR("Failed to allocate memory\n");
910 return E_OUTOFMEMORY;
913 FIXME("Ignoring access flags (pool)\n");
915 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
916 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
919 WARN("Failed to initialize buffer, hr %#x.\n", hr);
920 HeapFree(GetProcessHeap(), 0, object);
923 object->desc = *desc;
925 TRACE("Created buffer %p.\n", object);
927 *buffer = (IWineD3DBuffer *)object;
932 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface,
933 UINT Size, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer,
934 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
936 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
937 struct wined3d_buffer *object;
940 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
941 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
943 if (Pool == WINED3DPOOL_SCRATCH)
945 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
946 * anyway, SCRATCH vertex buffers aren't usable anywhere
948 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
949 *ppVertexBuffer = NULL;
950 return WINED3DERR_INVALIDCALL;
953 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
956 ERR("Out of memory\n");
957 *ppVertexBuffer = NULL;
958 return WINED3DERR_OUTOFVIDEOMEMORY;
961 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
962 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
965 WARN("Failed to initialize buffer, hr %#x.\n", hr);
966 HeapFree(GetProcessHeap(), 0, object);
970 TRACE("Created buffer %p.\n", object);
971 *ppVertexBuffer = (IWineD3DBuffer *)object;
976 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
977 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer,
978 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
980 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
981 struct wined3d_buffer *object;
984 TRACE("(%p) Creating index buffer\n", This);
986 /* Allocate the storage for the device */
987 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
990 ERR("Out of memory\n");
991 *ppIndexBuffer = NULL;
992 return WINED3DERR_OUTOFVIDEOMEMORY;
995 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
996 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
1000 WARN("Failed to initialize buffer, hr %#x\n", hr);
1001 HeapFree(GetProcessHeap(), 0, object);
1005 TRACE("Created buffer %p.\n", object);
1007 *ppIndexBuffer = (IWineD3DBuffer *) object;
1012 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
1013 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock)
1015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1016 IWineD3DStateBlockImpl *object;
1019 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1022 ERR("Failed to allocate stateblock memory.\n");
1023 return E_OUTOFMEMORY;
1026 hr = stateblock_init(object, This, type);
1029 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
1030 HeapFree(GetProcessHeap(), 0, object);
1034 TRACE("Created stateblock %p.\n", object);
1035 *stateblock = (IWineD3DStateBlock *)object;
1040 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
1041 enum wined3d_format_id Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **surface,
1042 DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
1043 WINED3DSURFTYPE Impl, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
1045 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1046 IWineD3DSurfaceImpl *object;
1049 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
1050 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
1051 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
1052 surface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
1053 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
1055 if (Impl == SURFACE_OPENGL && !This->adapter)
1057 ERR("OpenGL surfaces are not available without OpenGL.\n");
1058 return WINED3DERR_NOTAVAILABLE;
1061 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1064 ERR("Failed to allocate surface memory.\n");
1065 return WINED3DERR_OUTOFVIDEOMEMORY;
1068 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
1069 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
1072 WARN("Failed to initialize surface, returning %#x.\n", hr);
1073 HeapFree(GetProcessHeap(), 0, object);
1077 TRACE("(%p) : Created surface %p\n", This, object);
1079 *surface = (IWineD3DSurface *)object;
1084 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
1085 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
1087 struct wined3d_rendertarget_view *object;
1089 TRACE("iface %p, resource %p, parent %p, rendertarget_view %p.\n",
1090 iface, resource, parent, rendertarget_view);
1092 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1095 ERR("Failed to allocate memory\n");
1096 return E_OUTOFMEMORY;
1099 wined3d_rendertarget_view_init(object, resource, parent);
1101 TRACE("Created render target view %p.\n", object);
1102 *rendertarget_view = (IWineD3DRendertargetView *)object;
1107 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
1108 UINT Width, UINT Height, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1109 IWineD3DTexture **ppTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
1111 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1112 IWineD3DTextureImpl *object;
1115 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
1116 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
1117 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
1119 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1122 ERR("Out of memory\n");
1124 return WINED3DERR_OUTOFVIDEOMEMORY;
1127 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
1130 WARN("Failed to initialize texture, returning %#x\n", hr);
1131 HeapFree(GetProcessHeap(), 0, object);
1136 *ppTexture = (IWineD3DTexture *)object;
1138 TRACE("(%p) : Created texture %p\n", This, object);
1143 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
1144 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool,
1145 IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
1147 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1148 IWineD3DVolumeTextureImpl *object;
1151 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1152 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1154 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1157 ERR("Out of memory\n");
1158 *ppVolumeTexture = NULL;
1159 return WINED3DERR_OUTOFVIDEOMEMORY;
1162 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
1165 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
1166 HeapFree(GetProcessHeap(), 0, object);
1167 *ppVolumeTexture = NULL;
1171 TRACE("(%p) : Created volume texture %p.\n", This, object);
1172 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
1177 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
1178 UINT Depth, DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, IWineD3DVolume **ppVolume,
1179 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
1181 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1182 IWineD3DVolumeImpl *object;
1185 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1186 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1188 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1191 ERR("Out of memory\n");
1193 return WINED3DERR_OUTOFVIDEOMEMORY;
1196 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
1199 WARN("Failed to initialize volume, returning %#x.\n", hr);
1200 HeapFree(GetProcessHeap(), 0, object);
1204 TRACE("(%p) : Created volume %p.\n", This, object);
1205 *ppVolume = (IWineD3DVolume *)object;
1210 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
1211 DWORD Usage, enum wined3d_format_id Format, WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture,
1212 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
1214 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1215 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1218 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1221 ERR("Out of memory\n");
1222 *ppCubeTexture = NULL;
1223 return WINED3DERR_OUTOFVIDEOMEMORY;
1226 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
1229 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1230 HeapFree(GetProcessHeap(), 0, object);
1231 *ppCubeTexture = NULL;
1235 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1236 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1241 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
1242 WINED3DQUERYTYPE type, IWineD3DQuery **query, IUnknown *parent)
1244 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1245 IWineD3DQueryImpl *object;
1248 TRACE("iface %p, type %#x, query %p, parent %p.\n", iface, type, query, parent);
1250 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1253 ERR("Failed to allocate query memory.\n");
1254 return E_OUTOFMEMORY;
1257 hr = query_init(object, This, type, parent);
1260 WARN("Failed to initialize query, hr %#x.\n", hr);
1261 HeapFree(GetProcessHeap(), 0, object);
1265 TRACE("Created query %p.\n", object);
1266 *query = (IWineD3DQuery *)object;
1271 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1272 WINED3DPRESENT_PARAMETERS *present_parameters, IWineD3DSwapChain **swapchain,
1273 IUnknown *parent, WINED3DSURFTYPE surface_type)
1275 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1276 IWineD3DSwapChainImpl *object;
1279 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1280 iface, present_parameters, swapchain, parent, surface_type);
1282 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1285 ERR("Failed to allocate swapchain memory.\n");
1286 return E_OUTOFMEMORY;
1289 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
1292 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1293 HeapFree(GetProcessHeap(), 0, object);
1297 TRACE("Created swapchain %p.\n", object);
1298 *swapchain = (IWineD3DSwapChain *)object;
1303 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1304 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1306 TRACE("(%p)\n", This);
1308 return This->NumberOfSwapChains;
1311 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1312 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1313 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1315 if(iSwapChain < This->NumberOfSwapChains) {
1316 *pSwapChain = This->swapchains[iSwapChain];
1317 IWineD3DSwapChain_AddRef(*pSwapChain);
1318 TRACE("(%p) returning %p\n", This, *pSwapChain);
1321 TRACE("Swapchain out of range\n");
1323 return WINED3DERR_INVALIDCALL;
1327 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1328 IWineD3DVertexDeclaration **declaration, IUnknown *parent, const struct wined3d_parent_ops *parent_ops,
1329 const WINED3DVERTEXELEMENT *elements, UINT element_count)
1331 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1332 IWineD3DVertexDeclarationImpl *object = NULL;
1335 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1336 iface, declaration, parent, elements, element_count);
1338 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1341 ERR("Failed to allocate vertex declaration memory.\n");
1342 return E_OUTOFMEMORY;
1345 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1348 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1349 HeapFree(GetProcessHeap(), 0, object);
1353 TRACE("Created vertex declaration %p.\n", object);
1354 *declaration = (IWineD3DVertexDeclaration *)object;
1359 struct wined3d_fvf_convert_state
1361 const struct wined3d_gl_info *gl_info;
1362 WINED3DVERTEXELEMENT *elements;
1367 static void append_decl_element(struct wined3d_fvf_convert_state *state,
1368 enum wined3d_format_id format, WINED3DDECLUSAGE usage, UINT usage_idx)
1370 WINED3DVERTEXELEMENT *elements = state->elements;
1371 const struct wined3d_format_desc *format_desc;
1372 UINT offset = state->offset;
1373 UINT idx = state->idx;
1375 elements[idx].format = format;
1376 elements[idx].input_slot = 0;
1377 elements[idx].offset = offset;
1378 elements[idx].output_slot = 0;
1379 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1380 elements[idx].usage = usage;
1381 elements[idx].usage_idx = usage_idx;
1383 format_desc = getFormatDescEntry(format, state->gl_info);
1384 state->offset += format_desc->component_count * format_desc->component_size;
1388 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1389 DWORD fvf, WINED3DVERTEXELEMENT **ppVertexElements)
1391 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1392 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1393 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1394 BOOL has_blend_idx = has_blend &&
1395 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1396 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1397 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1398 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1399 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1400 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1401 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1403 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1404 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1405 struct wined3d_fvf_convert_state state;
1408 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1409 if (has_blend_idx) num_blends--;
1411 /* Compute declaration size */
1412 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1413 has_psize + has_diffuse + has_specular + num_textures;
1415 state.gl_info = gl_info;
1416 state.elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*state.elements));
1417 if (!state.elements) return ~0U;
1423 if (!has_blend && (fvf & WINED3DFVF_XYZRHW))
1424 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITIONT, 0);
1425 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW)
1426 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1428 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1431 if (has_blend && (num_blends > 0))
1433 if ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1434 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1440 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1443 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1446 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1449 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1452 ERR("Unexpected amount of blend values: %u\n", num_blends);
1459 if ((fvf & WINED3DFVF_LASTBETA_UBYTE4)
1460 || ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1461 append_decl_element(&state, WINED3DFMT_R8G8B8A8_UINT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1462 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1463 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDINDICES, 0);
1465 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1468 if (has_normal) append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_NORMAL, 0);
1469 if (has_psize) append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_PSIZE, 0);
1470 if (has_diffuse) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 0);
1471 if (has_specular) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 1);
1473 for (idx = 0; idx < num_textures; ++idx)
1475 switch ((texcoords >> (idx * 2)) & 0x03)
1477 case WINED3DFVF_TEXTUREFORMAT1:
1478 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1480 case WINED3DFVF_TEXTUREFORMAT2:
1481 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1483 case WINED3DFVF_TEXTUREFORMAT3:
1484 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1486 case WINED3DFVF_TEXTUREFORMAT4:
1487 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1492 *ppVertexElements = state.elements;
1496 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1497 IWineD3DVertexDeclaration **declaration, IUnknown *parent,
1498 const struct wined3d_parent_ops *parent_ops, DWORD fvf)
1500 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1501 WINED3DVERTEXELEMENT *elements;
1505 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1507 size = ConvertFvfToDeclaration(This, fvf, &elements);
1508 if (size == ~0U) return E_OUTOFMEMORY;
1510 hr = IWineD3DDevice_CreateVertexDeclaration(iface, declaration, parent, parent_ops, elements, size);
1511 HeapFree(GetProcessHeap(), 0, elements);
1515 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1516 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1517 IWineD3DVertexShader **ppVertexShader, IUnknown *parent,
1518 const struct wined3d_parent_ops *parent_ops)
1520 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1521 IWineD3DVertexShaderImpl *object;
1524 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1527 ERR("Failed to allocate shader memory.\n");
1528 return E_OUTOFMEMORY;
1531 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1534 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1535 HeapFree(GetProcessHeap(), 0, object);
1539 TRACE("Created vertex shader %p.\n", object);
1540 *ppVertexShader = (IWineD3DVertexShader *)object;
1545 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1546 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1547 IWineD3DGeometryShader **shader, IUnknown *parent,
1548 const struct wined3d_parent_ops *parent_ops)
1550 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1551 struct wined3d_geometryshader *object;
1554 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1557 ERR("Failed to allocate shader memory.\n");
1558 return E_OUTOFMEMORY;
1561 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1564 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1565 HeapFree(GetProcessHeap(), 0, object);
1569 TRACE("Created geometry shader %p.\n", object);
1570 *shader = (IWineD3DGeometryShader *)object;
1575 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1576 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1577 IWineD3DPixelShader **ppPixelShader, IUnknown *parent,
1578 const struct wined3d_parent_ops *parent_ops)
1580 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1581 IWineD3DPixelShaderImpl *object;
1584 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1587 ERR("Failed to allocate shader memory.\n");
1588 return E_OUTOFMEMORY;
1591 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1594 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1595 HeapFree(GetProcessHeap(), 0, object);
1599 TRACE("Created pixel shader %p.\n", object);
1600 *ppPixelShader = (IWineD3DPixelShader *)object;
1605 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1606 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1608 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1609 IWineD3DPaletteImpl *object;
1612 TRACE("iface %p, flags %#x, entries %p, palette %p, parent %p.\n",
1613 iface, Flags, PalEnt, Palette, Parent);
1615 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1618 ERR("Failed to allocate palette memory.\n");
1619 return E_OUTOFMEMORY;
1622 hr = wined3d_palette_init(object, This, Flags, PalEnt, Parent);
1625 WARN("Failed to initialize palette, hr %#x.\n", hr);
1626 HeapFree(GetProcessHeap(), 0, object);
1630 TRACE("Created palette %p.\n", object);
1631 *Palette = (IWineD3DPalette *)object;
1636 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1640 HDC dcb = NULL, dcs = NULL;
1641 WINEDDCOLORKEY colorkey;
1643 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1646 GetObjectA(hbm, sizeof(BITMAP), &bm);
1647 dcb = CreateCompatibleDC(NULL);
1649 SelectObject(dcb, hbm);
1653 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1654 * couldn't be loaded
1656 memset(&bm, 0, sizeof(bm));
1661 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1662 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1663 NULL, &wined3d_null_parent_ops);
1665 ERR("Wine logo requested, but failed to create surface\n");
1670 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1671 if(FAILED(hr)) goto out;
1672 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1673 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1675 colorkey.dwColorSpaceLowValue = 0;
1676 colorkey.dwColorSpaceHighValue = 0;
1677 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1681 const WINED3DCOLORVALUE c = {1.0f, 1.0f, 1.0f, 1.0f};
1682 /* Fill the surface with a white color to show that wined3d is there */
1683 IWineD3DDevice_ColorFill((IWineD3DDevice *)This, This->logo_surface, NULL, &c);
1687 if (dcb) DeleteDC(dcb);
1688 if (hbm) DeleteObject(hbm);
1691 /* Context activation is done by the caller. */
1692 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1694 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1696 /* Under DirectX you can have texture stage operations even if no texture is
1697 bound, whereas opengl will only do texture operations when a valid texture is
1698 bound. We emulate this by creating dummy textures and binding them to each
1699 texture stage, but disable all stages by default. Hence if a stage is enabled
1700 then the default texture will kick in until replaced by a SetTexture call */
1703 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1705 /* The dummy texture does not have client storage backing */
1706 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1707 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1710 for (i = 0; i < gl_info->limits.textures; ++i)
1712 GLubyte white = 255;
1714 /* Make appropriate texture active */
1715 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1716 checkGLcall("glActiveTextureARB");
1718 /* Generate an opengl texture name */
1719 glGenTextures(1, &This->dummyTextureName[i]);
1720 checkGLcall("glGenTextures");
1721 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1723 /* Generate a dummy 2d texture (not using 1d because they cause many
1724 * DRI drivers fall back to sw) */
1725 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1726 checkGLcall("glBindTexture");
1728 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1729 checkGLcall("glTexImage2D");
1732 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1734 /* Reenable because if supported it is enabled by default */
1735 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1736 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1742 /* Context activation is done by the caller. */
1743 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1746 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1747 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1750 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1753 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1755 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1757 if (!wined3d_register_window(window, device))
1759 ERR("Failed to register window %p.\n", window);
1763 device->focus_window = window;
1764 SetForegroundWindow(window);
1769 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1771 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1773 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1774 device->focus_window = NULL;
1777 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1778 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1780 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1781 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1782 IWineD3DSwapChainImpl *swapchain = NULL;
1783 struct wined3d_context *context;
1788 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1790 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1791 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1793 TRACE("(%p) : Creating stateblock\n", This);
1794 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
1797 WARN("Failed to create stateblock\n");
1800 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1801 This->updateStateBlock = This->stateBlock;
1802 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1804 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1805 sizeof(*This->render_targets) * gl_info->limits.buffers);
1807 This->NumberOfPalettes = 1;
1808 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1809 if (!This->palettes || !This->render_targets)
1811 ERR("Out of memory!\n");
1815 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1816 if(!This->palettes[0]) {
1817 ERR("Out of memory!\n");
1821 for (i = 0; i < 256; ++i) {
1822 This->palettes[0][i].peRed = 0xFF;
1823 This->palettes[0][i].peGreen = 0xFF;
1824 This->palettes[0][i].peBlue = 0xFF;
1825 This->palettes[0][i].peFlags = 0xFF;
1827 This->currentPalette = 0;
1829 /* Initialize the texture unit mapping to a 1:1 mapping */
1830 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1832 if (state < gl_info->limits.fragment_samplers)
1834 This->texUnitMap[state] = state;
1835 This->rev_tex_unit_map[state] = state;
1837 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1838 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1842 /* Setup the implicit swapchain. This also initializes a context. */
1843 TRACE("Creating implicit swapchain\n");
1844 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1845 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1848 WARN("Failed to create implicit swapchain\n");
1852 This->NumberOfSwapChains = 1;
1853 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1854 if(!This->swapchains) {
1855 ERR("Out of memory!\n");
1858 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1860 if (swapchain->back_buffers && swapchain->back_buffers[0])
1862 TRACE("Setting rendertarget to %p.\n", swapchain->back_buffers);
1863 This->render_targets[0] = swapchain->back_buffers[0];
1867 TRACE("Setting rendertarget to %p.\n", swapchain->front_buffer);
1868 This->render_targets[0] = swapchain->front_buffer;
1870 IWineD3DSurface_AddRef((IWineD3DSurface *)This->render_targets[0]);
1872 /* Depth Stencil support */
1873 This->depth_stencil = This->auto_depth_stencil;
1874 if (This->depth_stencil)
1875 IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
1877 hr = This->shader_backend->shader_alloc_private(iface);
1879 TRACE("Shader private data couldn't be allocated\n");
1882 hr = This->frag_pipe->alloc_private(iface);
1884 TRACE("Fragment pipeline private data couldn't be allocated\n");
1887 hr = This->blitter->alloc_private(iface);
1889 TRACE("Blitter private data couldn't be allocated\n");
1893 /* Set up some starting GL setup */
1895 /* Setup all the devices defaults */
1896 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1898 context = context_acquire(This, swapchain->front_buffer);
1900 create_dummy_textures(This);
1904 /* Initialize the current view state */
1905 This->view_ident = 1;
1906 This->contexts[0]->last_was_rhw = 0;
1907 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1908 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1910 switch(wined3d_settings.offscreen_rendering_mode) {
1912 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1915 case ORM_BACKBUFFER:
1917 if (context_get_current()->aux_buffers > 0)
1919 TRACE("Using auxilliary buffer for offscreen rendering\n");
1920 This->offscreenBuffer = GL_AUX0;
1922 TRACE("Using back buffer for offscreen rendering\n");
1923 This->offscreenBuffer = GL_BACK;
1928 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1931 context_release(context);
1933 /* Clear the screen */
1934 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1935 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1938 This->d3d_initialized = TRUE;
1940 if(wined3d_settings.logo) {
1941 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1943 This->highest_dirty_ps_const = 0;
1944 This->highest_dirty_vs_const = 0;
1948 HeapFree(GetProcessHeap(), 0, This->render_targets);
1949 HeapFree(GetProcessHeap(), 0, This->swapchains);
1950 This->NumberOfSwapChains = 0;
1951 if(This->palettes) {
1952 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1953 HeapFree(GetProcessHeap(), 0, This->palettes);
1955 This->NumberOfPalettes = 0;
1957 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1959 if(This->stateBlock) {
1960 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1961 This->stateBlock = NULL;
1963 if (This->blit_priv) {
1964 This->blitter->free_private(iface);
1966 if (This->fragment_priv) {
1967 This->frag_pipe->free_private(iface);
1969 if (This->shader_priv) {
1970 This->shader_backend->shader_free_private(iface);
1975 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1976 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1978 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1979 IWineD3DSwapChainImpl *swapchain = NULL;
1982 /* Setup the implicit swapchain */
1983 TRACE("Creating implicit swapchain\n");
1984 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1985 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1988 WARN("Failed to create implicit swapchain\n");
1992 This->NumberOfSwapChains = 1;
1993 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1994 if(!This->swapchains) {
1995 ERR("Out of memory!\n");
1998 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2002 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2006 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
2008 IWineD3DResource_UnLoad(resource);
2009 IWineD3DResource_Release(resource);
2013 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
2014 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
2016 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2017 const struct wined3d_gl_info *gl_info;
2018 struct wined3d_context *context;
2021 TRACE("(%p)\n", This);
2023 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2025 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2026 * it was created. Thus make sure a context is active for the glDelete* calls
2028 context = context_acquire(This, NULL);
2029 gl_info = context->gl_info;
2031 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2033 /* Unload resources */
2034 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
2036 TRACE("Deleting high order patches\n");
2037 for(i = 0; i < PATCHMAP_SIZE; i++) {
2038 struct list *e1, *e2;
2039 struct WineD3DRectPatch *patch;
2040 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2041 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2042 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2046 /* Delete the mouse cursor texture */
2047 if(This->cursorTexture) {
2049 glDeleteTextures(1, &This->cursorTexture);
2051 This->cursorTexture = 0;
2054 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2055 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2057 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2058 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2061 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2062 * private data, it might contain opengl pointers
2064 if(This->depth_blt_texture) {
2066 glDeleteTextures(1, &This->depth_blt_texture);
2068 This->depth_blt_texture = 0;
2070 if (This->depth_blt_rb) {
2072 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
2074 This->depth_blt_rb = 0;
2075 This->depth_blt_rb_w = 0;
2076 This->depth_blt_rb_h = 0;
2079 /* Release the update stateblock */
2080 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2081 if(This->updateStateBlock != This->stateBlock)
2082 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2084 This->updateStateBlock = NULL;
2086 { /* because were not doing proper internal refcounts releasing the primary state block
2087 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2088 to set this->stateBlock = NULL; first */
2089 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2090 This->stateBlock = NULL;
2092 /* Release the stateblock */
2093 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2094 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2098 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2099 This->blitter->free_private(iface);
2100 This->frag_pipe->free_private(iface);
2101 This->shader_backend->shader_free_private(iface);
2103 /* Release the buffers (with sanity checks)*/
2104 if (This->onscreen_depth_stencil)
2106 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
2107 This->onscreen_depth_stencil = NULL;
2110 TRACE("Releasing the depth stencil buffer at %p\n", This->depth_stencil);
2111 if (This->depth_stencil && IWineD3DSurface_Release((IWineD3DSurface *)This->depth_stencil))
2113 if (This->auto_depth_stencil != This->depth_stencil)
2114 FIXME("(%p) Something is still holding the depth/stencil buffer.\n",This);
2116 This->depth_stencil = NULL;
2118 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2119 IWineD3DSurface_Release((IWineD3DSurface *)This->render_targets[0]);
2121 TRACE("Setting rendertarget to NULL\n");
2122 This->render_targets[0] = NULL;
2124 if (This->auto_depth_stencil)
2126 if (IWineD3DSurface_Release((IWineD3DSurface *)This->auto_depth_stencil))
2128 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2130 This->auto_depth_stencil = NULL;
2133 context_release(context);
2135 for(i=0; i < This->NumberOfSwapChains; i++) {
2136 TRACE("Releasing the implicit swapchain %d\n", i);
2137 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2138 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2142 HeapFree(GetProcessHeap(), 0, This->swapchains);
2143 This->swapchains = NULL;
2144 This->NumberOfSwapChains = 0;
2146 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2147 HeapFree(GetProcessHeap(), 0, This->palettes);
2148 This->palettes = NULL;
2149 This->NumberOfPalettes = 0;
2151 HeapFree(GetProcessHeap(), 0, This->render_targets);
2152 This->render_targets = NULL;
2154 This->d3d_initialized = FALSE;
2159 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2163 for(i=0; i < This->NumberOfSwapChains; i++) {
2164 TRACE("Releasing the implicit swapchain %d\n", i);
2165 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2166 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2170 HeapFree(GetProcessHeap(), 0, This->swapchains);
2171 This->swapchains = NULL;
2172 This->NumberOfSwapChains = 0;
2176 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2177 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2178 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2180 * There is no way to deactivate thread safety once it is enabled.
2182 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2183 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2185 /*For now just store the flag(needed in case of ddraw) */
2186 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2189 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2190 const WINED3DDISPLAYMODE* pMode) {
2192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2193 const struct wined3d_format_desc *format_desc = getFormatDescEntry(pMode->Format, &This->adapter->gl_info);
2197 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2199 /* Resize the screen even without a window:
2200 * The app could have unset it with SetCooperativeLevel, but not called
2201 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2202 * but we don't have any hwnd
2205 memset(&devmode, 0, sizeof(devmode));
2206 devmode.dmSize = sizeof(devmode);
2207 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2208 devmode.dmBitsPerPel = format_desc->byte_count * 8;
2209 devmode.dmPelsWidth = pMode->Width;
2210 devmode.dmPelsHeight = pMode->Height;
2212 devmode.dmDisplayFrequency = pMode->RefreshRate;
2213 if (pMode->RefreshRate != 0) {
2214 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2217 /* Only change the mode if necessary */
2218 if( (This->ddraw_width == pMode->Width) &&
2219 (This->ddraw_height == pMode->Height) &&
2220 (This->ddraw_format == pMode->Format) &&
2221 (pMode->RefreshRate == 0) ) {
2225 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2226 if (ret != DISP_CHANGE_SUCCESSFUL) {
2227 if(devmode.dmDisplayFrequency != 0) {
2228 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2229 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2230 devmode.dmDisplayFrequency = 0;
2231 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2233 if(ret != DISP_CHANGE_SUCCESSFUL) {
2234 return WINED3DERR_NOTAVAILABLE;
2238 /* Store the new values */
2239 This->ddraw_width = pMode->Width;
2240 This->ddraw_height = pMode->Height;
2241 This->ddraw_format = pMode->Format;
2243 /* And finally clip mouse to our screen */
2244 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2245 ClipCursor(&clip_rc);
2250 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2252 *ppD3D = This->wined3d;
2253 TRACE("Returning %p.\n", *ppD3D);
2254 IWineD3D_AddRef(*ppD3D);
2258 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2259 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2261 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2262 (This->adapter->TextureRam/(1024*1024)),
2263 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2264 /* return simulated texture memory left */
2265 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2269 * Get / Set Stream Source
2271 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2272 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2274 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2275 IWineD3DBuffer *oldSrc;
2277 if (StreamNumber >= MAX_STREAMS) {
2278 WARN("Stream out of range %d\n", StreamNumber);
2279 return WINED3DERR_INVALIDCALL;
2280 } else if(OffsetInBytes & 0x3) {
2281 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2282 return WINED3DERR_INVALIDCALL;
2285 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2286 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2288 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2290 if(oldSrc == pStreamData &&
2291 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2292 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2293 TRACE("Application is setting the old values over, nothing to do\n");
2297 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2299 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2300 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2303 /* Handle recording of state blocks */
2304 if (This->isRecordingState) {
2305 TRACE("Recording... not performing anything\n");
2306 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2307 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2311 if (pStreamData != NULL) {
2312 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2313 IWineD3DBuffer_AddRef(pStreamData);
2315 if (oldSrc != NULL) {
2316 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2317 IWineD3DBuffer_Release(oldSrc);
2320 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2325 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2326 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2330 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2331 This->stateBlock->streamSource[StreamNumber],
2332 This->stateBlock->streamOffset[StreamNumber],
2333 This->stateBlock->streamStride[StreamNumber]);
2335 if (StreamNumber >= MAX_STREAMS) {
2336 WARN("Stream out of range %d\n", StreamNumber);
2337 return WINED3DERR_INVALIDCALL;
2339 *pStream = This->stateBlock->streamSource[StreamNumber];
2340 *pStride = This->stateBlock->streamStride[StreamNumber];
2342 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2345 if (*pStream != NULL) {
2346 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2351 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2352 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2353 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2354 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2356 /* Verify input at least in d3d9 this is invalid*/
2357 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2358 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2359 return WINED3DERR_INVALIDCALL;
2361 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2362 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2363 return WINED3DERR_INVALIDCALL;
2366 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2367 return WINED3DERR_INVALIDCALL;
2370 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2371 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2373 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2374 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2376 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2377 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2378 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2384 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2387 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2388 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2390 TRACE("(%p) : returning %d\n", This, *Divider);
2396 * Get / Set & Multiply Transform
2398 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2401 /* Most of this routine, comments included copied from ddraw tree initially: */
2402 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2404 /* Handle recording of state blocks */
2405 if (This->isRecordingState) {
2406 TRACE("Recording... not performing anything\n");
2407 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2408 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2413 * If the new matrix is the same as the current one,
2414 * we cut off any further processing. this seems to be a reasonable
2415 * optimization because as was noticed, some apps (warcraft3 for example)
2416 * tend towards setting the same matrix repeatedly for some reason.
2418 * From here on we assume that the new matrix is different, wherever it matters.
2420 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2421 TRACE("The app is setting the same matrix over again\n");
2424 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2428 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2429 where ViewMat = Camera space, WorldMat = world space.
2431 In OpenGL, camera and world space is combined into GL_MODELVIEW
2432 matrix. The Projection matrix stay projection matrix.
2435 /* Capture the times we can just ignore the change for now */
2436 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2437 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2438 /* Handled by the state manager */
2441 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2445 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2446 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2447 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2448 *pMatrix = This->stateBlock->transforms[State];
2452 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2453 const WINED3DMATRIX *mat = NULL;
2456 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2457 * below means it will be recorded in a state block change, but it
2458 * works regardless where it is recorded.
2459 * If this is found to be wrong, change to StateBlock.
2461 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2462 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2464 if (State <= HIGHEST_TRANSFORMSTATE)
2466 mat = &This->updateStateBlock->transforms[State];
2468 FIXME("Unhandled transform state!!\n");
2471 multiply_matrix(&temp, mat, pMatrix);
2473 /* Apply change via set transform - will reapply to eg. lights this way */
2474 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2480 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2481 you can reference any indexes you want as long as that number max are enabled at any
2482 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2483 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2484 but when recording, just build a chain pretty much of commands to be replayed. */
2486 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2488 struct wined3d_light_info *object = NULL;
2489 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2492 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2493 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2495 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2499 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2500 return WINED3DERR_INVALIDCALL;
2503 switch(pLight->Type) {
2504 case WINED3DLIGHT_POINT:
2505 case WINED3DLIGHT_SPOT:
2506 case WINED3DLIGHT_PARALLELPOINT:
2507 case WINED3DLIGHT_GLSPOT:
2508 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2511 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2513 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2514 return WINED3DERR_INVALIDCALL;
2518 case WINED3DLIGHT_DIRECTIONAL:
2519 /* Ignores attenuation */
2523 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2524 return WINED3DERR_INVALIDCALL;
2527 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2529 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2530 if(object->OriginalIndex == Index) break;
2535 TRACE("Adding new light\n");
2536 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2538 ERR("Out of memory error when allocating a light\n");
2539 return E_OUTOFMEMORY;
2541 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2542 object->glIndex = -1;
2543 object->OriginalIndex = Index;
2546 /* Initialize the object */
2547 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,
2548 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2549 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2550 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2551 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2552 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2553 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2555 /* Save away the information */
2556 object->OriginalParms = *pLight;
2558 switch (pLight->Type) {
2559 case WINED3DLIGHT_POINT:
2561 object->lightPosn[0] = pLight->Position.x;
2562 object->lightPosn[1] = pLight->Position.y;
2563 object->lightPosn[2] = pLight->Position.z;
2564 object->lightPosn[3] = 1.0f;
2565 object->cutoff = 180.0f;
2569 case WINED3DLIGHT_DIRECTIONAL:
2571 object->lightPosn[0] = -pLight->Direction.x;
2572 object->lightPosn[1] = -pLight->Direction.y;
2573 object->lightPosn[2] = -pLight->Direction.z;
2574 object->lightPosn[3] = 0.0f;
2575 object->exponent = 0.0f;
2576 object->cutoff = 180.0f;
2579 case WINED3DLIGHT_SPOT:
2581 object->lightPosn[0] = pLight->Position.x;
2582 object->lightPosn[1] = pLight->Position.y;
2583 object->lightPosn[2] = pLight->Position.z;
2584 object->lightPosn[3] = 1.0f;
2587 object->lightDirn[0] = pLight->Direction.x;
2588 object->lightDirn[1] = pLight->Direction.y;
2589 object->lightDirn[2] = pLight->Direction.z;
2590 object->lightDirn[3] = 1.0f;
2593 * opengl-ish and d3d-ish spot lights use too different models for the
2594 * light "intensity" as a function of the angle towards the main light direction,
2595 * so we only can approximate very roughly.
2596 * however spot lights are rather rarely used in games (if ever used at all).
2597 * furthermore if still used, probably nobody pays attention to such details.
2599 if (pLight->Falloff == 0) {
2600 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2601 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2602 * will always be 1.0 for both of them, and we don't have to care for the
2603 * rest of the rather complex calculation
2605 object->exponent = 0.0f;
2607 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2608 if (rho < 0.0001f) rho = 0.0001f;
2609 object->exponent = -0.3f/logf(cosf(rho/2));
2611 if (object->exponent > 128.0f)
2613 object->exponent = 128.0f;
2615 object->cutoff = (float) (pLight->Phi*90/M_PI);
2621 FIXME("Unrecognized light type %d\n", pLight->Type);
2624 /* Update the live definitions if the light is currently assigned a glIndex */
2625 if (object->glIndex != -1 && !This->isRecordingState) {
2626 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2631 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2633 struct wined3d_light_info *lightInfo = NULL;
2634 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2635 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2637 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2639 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2641 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2642 if(lightInfo->OriginalIndex == Index) break;
2646 if (lightInfo == NULL) {
2647 TRACE("Light information requested but light not defined\n");
2648 return WINED3DERR_INVALIDCALL;
2651 *pLight = lightInfo->OriginalParms;
2656 * Get / Set Light Enable
2657 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2659 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2661 struct wined3d_light_info *lightInfo = NULL;
2662 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2663 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2665 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2667 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2669 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2670 if(lightInfo->OriginalIndex == Index) break;
2673 TRACE("Found light: %p\n", lightInfo);
2675 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2676 if (lightInfo == NULL) {
2678 TRACE("Light enabled requested but light not defined, so defining one!\n");
2679 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2681 /* Search for it again! Should be fairly quick as near head of list */
2682 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2684 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2685 if(lightInfo->OriginalIndex == Index) break;
2688 if (lightInfo == NULL) {
2689 FIXME("Adding default lights has failed dismally\n");
2690 return WINED3DERR_INVALIDCALL;
2695 if(lightInfo->glIndex != -1) {
2696 if(!This->isRecordingState) {
2697 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2700 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2701 lightInfo->glIndex = -1;
2703 TRACE("Light already disabled, nothing to do\n");
2705 lightInfo->enabled = FALSE;
2707 lightInfo->enabled = TRUE;
2708 if (lightInfo->glIndex != -1) {
2710 TRACE("Nothing to do as light was enabled\n");
2713 /* Find a free gl light */
2714 for(i = 0; i < This->maxConcurrentLights; i++) {
2715 if(This->updateStateBlock->activeLights[i] == NULL) {
2716 This->updateStateBlock->activeLights[i] = lightInfo;
2717 lightInfo->glIndex = i;
2721 if(lightInfo->glIndex == -1) {
2722 /* Our tests show that Windows returns D3D_OK in this situation, even with
2723 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2724 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2725 * as well for those lights.
2727 * TODO: Test how this affects rendering
2729 WARN("Too many concurrently active lights\n");
2733 /* i == lightInfo->glIndex */
2734 if(!This->isRecordingState) {
2735 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2743 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2745 struct wined3d_light_info *lightInfo = NULL;
2746 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2748 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2749 TRACE("(%p) : for idx(%d)\n", This, Index);
2751 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2753 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2754 if(lightInfo->OriginalIndex == Index) break;
2758 if (lightInfo == NULL) {
2759 TRACE("Light enabled state requested but light not defined\n");
2760 return WINED3DERR_INVALIDCALL;
2762 /* true is 128 according to SetLightEnable */
2763 *pEnable = lightInfo->enabled ? 128 : 0;
2768 * Get / Set Clip Planes
2770 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2771 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2772 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2774 /* Validate Index */
2775 if (Index >= This->adapter->gl_info.limits.clipplanes)
2777 TRACE("Application has requested clipplane this device doesn't support\n");
2778 return WINED3DERR_INVALIDCALL;
2781 This->updateStateBlock->changed.clipplane |= 1 << Index;
2783 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2784 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2785 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2786 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2787 TRACE("Application is setting old values over, nothing to do\n");
2791 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2792 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2793 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2794 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2796 /* Handle recording of state blocks */
2797 if (This->isRecordingState) {
2798 TRACE("Recording... not performing anything\n");
2802 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2807 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2808 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2809 TRACE("(%p) : for idx %d\n", This, Index);
2811 /* Validate Index */
2812 if (Index >= This->adapter->gl_info.limits.clipplanes)
2814 TRACE("Application has requested clipplane this device doesn't support\n");
2815 return WINED3DERR_INVALIDCALL;
2818 pPlane[0] = (float) This->stateBlock->clipplane[Index][0];
2819 pPlane[1] = (float) This->stateBlock->clipplane[Index][1];
2820 pPlane[2] = (float) This->stateBlock->clipplane[Index][2];
2821 pPlane[3] = (float) This->stateBlock->clipplane[Index][3];
2826 * Get / Set Clip Plane Status
2827 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2829 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2830 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2831 FIXME("(%p) : stub\n", This);
2832 if (NULL == pClipStatus) {
2833 return WINED3DERR_INVALIDCALL;
2835 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2836 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2840 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2842 FIXME("(%p) : stub\n", This);
2843 if (NULL == pClipStatus) {
2844 return WINED3DERR_INVALIDCALL;
2846 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2847 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2852 * Get / Set Material
2854 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2857 This->updateStateBlock->changed.material = TRUE;
2858 This->updateStateBlock->material = *pMaterial;
2860 /* Handle recording of state blocks */
2861 if (This->isRecordingState) {
2862 TRACE("Recording... not performing anything\n");
2866 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2870 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2871 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2872 *pMaterial = This->updateStateBlock->material;
2873 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2874 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2875 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2876 pMaterial->Ambient.b, pMaterial->Ambient.a);
2877 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2878 pMaterial->Specular.b, pMaterial->Specular.a);
2879 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2880 pMaterial->Emissive.b, pMaterial->Emissive.a);
2881 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2889 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2890 IWineD3DBuffer *pIndexData, enum wined3d_format_id fmt)
2892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2893 IWineD3DBuffer *oldIdxs;
2895 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2896 oldIdxs = This->updateStateBlock->pIndexData;
2898 This->updateStateBlock->changed.indices = TRUE;
2899 This->updateStateBlock->pIndexData = pIndexData;
2900 This->updateStateBlock->IndexFmt = fmt;
2902 /* Handle recording of state blocks */
2903 if (This->isRecordingState) {
2904 TRACE("Recording... not performing anything\n");
2905 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2906 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2910 if(oldIdxs != pIndexData) {
2911 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2913 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2914 IWineD3DBuffer_AddRef(pIndexData);
2917 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2918 IWineD3DBuffer_Release(oldIdxs);
2925 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2927 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2929 *ppIndexData = This->stateBlock->pIndexData;
2931 /* up ref count on ppindexdata */
2933 IWineD3DBuffer_AddRef(*ppIndexData);
2934 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2936 TRACE("(%p) No index data set\n", This);
2938 TRACE("Returning %p\n", *ppIndexData);
2943 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2944 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2945 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2946 TRACE("(%p)->(%d)\n", This, BaseIndex);
2948 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2949 TRACE("Application is setting the old value over, nothing to do\n");
2953 This->updateStateBlock->baseVertexIndex = BaseIndex;
2955 if (This->isRecordingState) {
2956 TRACE("Recording... not performing anything\n");
2959 /* The base vertex index affects the stream sources */
2960 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2964 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2965 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2966 TRACE("(%p) : base_index %p\n", This, base_index);
2968 *base_index = This->stateBlock->baseVertexIndex;
2970 TRACE("Returning %u\n", *base_index);
2976 * Get / Set Viewports
2978 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2979 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2981 TRACE("(%p)\n", This);
2982 This->updateStateBlock->changed.viewport = TRUE;
2983 This->updateStateBlock->viewport = *pViewport;
2985 /* Handle recording of state blocks */
2986 if (This->isRecordingState) {
2987 TRACE("Recording... not performing anything\n");
2991 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2992 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2994 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2999 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3000 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3001 TRACE("(%p)\n", This);
3002 *pViewport = This->stateBlock->viewport;
3007 * Get / Set Render States
3008 * TODO: Verify against dx9 definitions
3010 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3013 DWORD oldValue = This->stateBlock->renderState[State];
3015 TRACE("iface %p, state %s (%#x), value %#x.\n", iface, debug_d3drenderstate(State), State, Value);
3017 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3018 This->updateStateBlock->renderState[State] = Value;
3020 /* Handle recording of state blocks */
3021 if (This->isRecordingState) {
3022 TRACE("Recording... not performing anything\n");
3026 /* Compared here and not before the assignment to allow proper stateblock recording */
3027 if(Value == oldValue) {
3028 TRACE("Application is setting the old value over, nothing to do\n");
3030 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3036 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3037 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3039 TRACE("iface %p, state %s (%#x), value %p.\n", iface, debug_d3drenderstate(State), State, pValue);
3041 *pValue = This->stateBlock->renderState[State];
3046 * Get / Set Sampler States
3047 * TODO: Verify against dx9 definitions
3050 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3051 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3054 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3055 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3057 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3058 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3061 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3062 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3063 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3066 * SetSampler is designed to allow for more than the standard up to 8 textures
3067 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3068 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3070 * http://developer.nvidia.com/object/General_FAQ.html#t6
3072 * There are two new settings for GForce
3074 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3075 * and the texture one:
3076 * GL_MAX_TEXTURE_COORDS_ARB.
3077 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3080 oldValue = This->stateBlock->samplerState[Sampler][Type];
3081 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3082 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3084 /* Handle recording of state blocks */
3085 if (This->isRecordingState) {
3086 TRACE("Recording... not performing anything\n");
3090 if(oldValue == Value) {
3091 TRACE("Application is setting the old value over, nothing to do\n");
3095 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3100 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3101 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3103 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3104 This, Sampler, debug_d3dsamplerstate(Type), Type);
3106 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3107 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3110 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3111 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3112 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3114 *Value = This->stateBlock->samplerState[Sampler][Type];
3115 TRACE("(%p) : Returning %#x\n", This, *Value);
3120 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3121 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3123 This->updateStateBlock->changed.scissorRect = TRUE;
3124 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3125 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3128 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3130 if(This->isRecordingState) {
3131 TRACE("Recording... not performing anything\n");
3135 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3140 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3141 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3143 *pRect = This->updateStateBlock->scissorRect;
3144 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3148 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3149 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3150 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3152 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3154 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
3155 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
3157 This->updateStateBlock->vertexDecl = pDecl;
3158 This->updateStateBlock->changed.vertexDecl = TRUE;
3160 if (This->isRecordingState) {
3161 TRACE("Recording... not performing anything\n");
3163 } else if(pDecl == oldDecl) {
3164 /* Checked after the assignment to allow proper stateblock recording */
3165 TRACE("Application is setting the old declaration over, nothing to do\n");
3169 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3173 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3174 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3176 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3178 *ppDecl = This->stateBlock->vertexDecl;
3179 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3183 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3184 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3185 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3187 This->updateStateBlock->vertexShader = pShader;
3188 This->updateStateBlock->changed.vertexShader = TRUE;
3190 if (This->isRecordingState) {
3191 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3192 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3193 TRACE("Recording... not performing anything\n");
3195 } else if(oldShader == pShader) {
3196 /* Checked here to allow proper stateblock recording */
3197 TRACE("App is setting the old shader over, nothing to do\n");
3201 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3202 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3203 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3205 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3210 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3213 if (NULL == ppShader) {
3214 return WINED3DERR_INVALIDCALL;
3216 *ppShader = This->stateBlock->vertexShader;
3217 if( NULL != *ppShader)
3218 IWineD3DVertexShader_AddRef(*ppShader);
3220 TRACE("(%p) : returning %p\n", This, *ppShader);
3224 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3225 IWineD3DDevice *iface,
3227 CONST BOOL *srcData,
3230 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3231 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3233 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3234 iface, srcData, start, count);
3236 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3238 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3239 for (i = 0; i < cnt; i++)
3240 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3242 for (i = start; i < cnt + start; ++i) {
3243 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3246 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3251 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3252 IWineD3DDevice *iface,
3257 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3258 int cnt = min(count, MAX_CONST_B - start);
3260 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3261 iface, dstData, start, count);
3263 if (dstData == NULL || cnt < 0)
3264 return WINED3DERR_INVALIDCALL;
3266 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3270 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3271 IWineD3DDevice *iface,
3276 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3277 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3279 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3280 iface, srcData, start, count);
3282 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3284 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3285 for (i = 0; i < cnt; i++)
3286 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3287 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3289 for (i = start; i < cnt + start; ++i) {
3290 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3293 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3298 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3299 IWineD3DDevice *iface,
3304 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3305 int cnt = min(count, MAX_CONST_I - start);
3307 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3308 iface, dstData, start, count);
3310 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= 0)
3311 return WINED3DERR_INVALIDCALL;
3313 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3317 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3318 IWineD3DDevice *iface,
3320 CONST float *srcData,
3323 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3326 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3327 iface, srcData, start, count);
3329 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3330 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3331 return WINED3DERR_INVALIDCALL;
3333 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3335 for (i = 0; i < count; i++)
3336 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3337 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3340 if (!This->isRecordingState)
3342 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3343 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3346 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3347 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3352 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3353 IWineD3DDevice *iface,
3358 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3359 int cnt = min(count, This->d3d_vshader_constantF - start);
3361 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3362 iface, dstData, start, count);
3364 if (dstData == NULL || cnt < 0)
3365 return WINED3DERR_INVALIDCALL;
3367 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3371 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3373 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3375 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3379 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3381 DWORD i = This->rev_tex_unit_map[unit];
3382 DWORD j = This->texUnitMap[stage];
3384 This->texUnitMap[stage] = unit;
3385 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3387 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3390 This->rev_tex_unit_map[unit] = stage;
3391 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3393 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3397 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3400 This->fixed_function_usage_map = 0;
3401 for (i = 0; i < MAX_TEXTURES; ++i) {
3402 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3403 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3404 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3405 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3406 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3407 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3408 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3409 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3411 if (color_op == WINED3DTOP_DISABLE) {
3412 /* Not used, and disable higher stages */
3416 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3417 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3418 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3419 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3420 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3421 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3422 This->fixed_function_usage_map |= (1 << i);
3425 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3426 This->fixed_function_usage_map |= (1 << (i + 1));
3431 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3433 unsigned int i, tex;
3436 device_update_fixed_function_usage_map(This);
3437 ffu_map = This->fixed_function_usage_map;
3439 if (This->max_ffp_textures == gl_info->limits.texture_stages
3440 || This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures)
3442 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3444 if (!(ffu_map & 1)) continue;
3446 if (This->texUnitMap[i] != i) {
3447 device_map_stage(This, i, i);
3448 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3449 markTextureStagesDirty(This, i);
3455 /* Now work out the mapping */
3457 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3459 if (!(ffu_map & 1)) continue;
3461 if (This->texUnitMap[i] != tex) {
3462 device_map_stage(This, i, tex);
3463 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3464 markTextureStagesDirty(This, i);
3471 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3473 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3474 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3477 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3478 if (sampler_type[i] && This->texUnitMap[i] != i)
3480 device_map_stage(This, i, i);
3481 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3482 if (i < gl_info->limits.texture_stages)
3484 markTextureStagesDirty(This, i);
3490 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_tokens,
3491 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_tokens, DWORD unit)
3493 DWORD current_mapping = This->rev_tex_unit_map[unit];
3495 /* Not currently used */
3496 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3498 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3499 /* Used by a fragment sampler */
3501 if (!pshader_sampler_tokens) {
3502 /* No pixel shader, check fixed function */
3503 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3506 /* Pixel shader, check the shader's sampler map */
3507 return !pshader_sampler_tokens[current_mapping];
3510 /* Used by a vertex sampler */
3511 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3514 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3516 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3517 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3518 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3519 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3523 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3525 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3526 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3527 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3530 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3531 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3532 if (vshader_sampler_type[i])
3534 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3536 /* Already mapped somewhere */
3540 while (start >= 0) {
3541 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3543 device_map_stage(This, vsampler_idx, start);
3544 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3556 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3558 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3559 BOOL vs = use_vs(This->stateBlock);
3560 BOOL ps = use_ps(This->stateBlock);
3563 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3564 * that would be really messy and require shader recompilation
3565 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3566 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3568 if (ps) device_map_psamplers(This, gl_info);
3569 else device_map_fixed_function_samplers(This, gl_info);
3571 if (vs) device_map_vsamplers(This, ps, gl_info);
3574 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3575 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3576 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3577 This->updateStateBlock->pixelShader = pShader;
3578 This->updateStateBlock->changed.pixelShader = TRUE;
3580 /* Handle recording of state blocks */
3581 if (This->isRecordingState) {
3582 TRACE("Recording... not performing anything\n");
3585 if (This->isRecordingState) {
3586 TRACE("Recording... not performing anything\n");
3587 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3588 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3592 if(pShader == oldShader) {
3593 TRACE("App is setting the old pixel shader over, nothing to do\n");
3597 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3598 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3600 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3601 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3606 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3607 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3609 if (NULL == ppShader) {
3610 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3611 return WINED3DERR_INVALIDCALL;
3614 *ppShader = This->stateBlock->pixelShader;
3615 if (NULL != *ppShader) {
3616 IWineD3DPixelShader_AddRef(*ppShader);
3618 TRACE("(%p) : returning %p\n", This, *ppShader);
3622 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3623 IWineD3DDevice *iface,
3625 CONST BOOL *srcData,
3628 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3629 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3631 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3632 iface, srcData, start, count);
3634 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3636 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3637 for (i = 0; i < cnt; i++)
3638 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3640 for (i = start; i < cnt + start; ++i) {
3641 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3644 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3649 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3650 IWineD3DDevice *iface,
3655 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3656 int cnt = min(count, MAX_CONST_B - start);
3658 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3659 iface, dstData, start, count);
3661 if (dstData == NULL || cnt < 0)
3662 return WINED3DERR_INVALIDCALL;
3664 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3668 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3669 IWineD3DDevice *iface,
3674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3675 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3677 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3678 iface, srcData, start, count);
3680 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3682 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3683 for (i = 0; i < cnt; i++)
3684 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3685 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3687 for (i = start; i < cnt + start; ++i) {
3688 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3691 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3696 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3697 IWineD3DDevice *iface,
3702 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3703 int cnt = min(count, MAX_CONST_I - start);
3705 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3706 iface, dstData, start, count);
3708 if (dstData == NULL || cnt < 0)
3709 return WINED3DERR_INVALIDCALL;
3711 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3715 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3716 IWineD3DDevice *iface,
3718 CONST float *srcData,
3721 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3724 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3725 iface, srcData, start, count);
3727 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3728 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3729 return WINED3DERR_INVALIDCALL;
3731 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3733 for (i = 0; i < count; i++)
3734 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3735 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3738 if (!This->isRecordingState)
3740 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3741 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3744 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3745 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3750 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3751 IWineD3DDevice *iface,
3756 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3757 int cnt = min(count, This->d3d_pshader_constantF - start);
3759 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3760 iface, dstData, start, count);
3762 if (dstData == NULL || cnt < 0)
3763 return WINED3DERR_INVALIDCALL;
3765 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3769 /* Context activation is done by the caller. */
3770 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3771 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3772 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3775 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3776 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3779 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3783 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3785 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3788 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3790 ERR("Source has no position mask\n");
3791 return WINED3DERR_INVALIDCALL;
3794 /* We might access VBOs from this code, so hold the lock */
3797 if (!dest->resource.allocatedMemory)
3798 buffer_get_sysmem(dest, gl_info);
3800 /* Get a pointer into the destination vbo(create one if none exists) and
3801 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3803 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3805 dest->flags |= WINED3D_BUFFER_CREATEBO;
3806 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3809 if (dest->buffer_object)
3811 unsigned char extrabytes = 0;
3812 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3813 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3814 * this may write 4 extra bytes beyond the area that should be written
3816 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3817 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3818 if(!dest_conv_addr) {
3819 ERR("Out of memory\n");
3820 /* Continue without storing converted vertices */
3822 dest_conv = dest_conv_addr;
3826 * a) WINED3DRS_CLIPPING is enabled
3827 * b) WINED3DVOP_CLIP is passed
3829 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3830 static BOOL warned = FALSE;
3832 * The clipping code is not quite correct. Some things need
3833 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3834 * so disable clipping for now.
3835 * (The graphics in Half-Life are broken, and my processvertices
3836 * test crashes with IDirect3DDevice3)
3842 FIXME("Clipping is broken and disabled for now\n");
3844 } else doClip = FALSE;
3845 dest_ptr = ((char *)buffer_get_sysmem(dest, gl_info)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3847 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3850 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3851 WINED3DTS_PROJECTION,
3853 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3854 WINED3DTS_WORLDMATRIX(0),
3857 TRACE("View mat:\n");
3858 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);
3859 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);
3860 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);
3861 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);
3863 TRACE("Proj mat:\n");
3864 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);
3865 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);
3866 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);
3867 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);
3869 TRACE("World mat:\n");
3870 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);
3871 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);
3872 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);
3873 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);
3875 /* Get the viewport */
3876 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3877 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3878 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3880 multiply_matrix(&mat,&view_mat,&world_mat);
3881 multiply_matrix(&mat,&proj_mat,&mat);
3883 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3885 for (i = 0; i < dwCount; i+= 1) {
3886 unsigned int tex_index;
3888 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3889 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3890 /* The position first */
3891 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3892 const float *p = (const float *)(element->data + i * element->stride);
3894 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3896 /* Multiplication with world, view and projection matrix */
3897 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);
3898 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);
3899 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);
3900 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);
3902 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3904 /* WARNING: The following things are taken from d3d7 and were not yet checked
3905 * against d3d8 or d3d9!
3908 /* Clipping conditions: From msdn
3910 * A vertex is clipped if it does not match the following requirements
3914 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3916 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3917 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3922 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3923 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3926 /* "Normal" viewport transformation (not clipped)
3927 * 1) The values are divided by rhw
3928 * 2) The y axis is negative, so multiply it with -1
3929 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3930 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3931 * 4) Multiply x with Width/2 and add Width/2
3932 * 5) The same for the height
3933 * 6) Add the viewpoint X and Y to the 2D coordinates and
3934 * The minimum Z value to z
3935 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3937 * Well, basically it's simply a linear transformation into viewport
3949 z *= vp.MaxZ - vp.MinZ;
3951 x += vp.Width / 2 + vp.X;
3952 y += vp.Height / 2 + vp.Y;
3957 /* That vertex got clipped
3958 * Contrary to OpenGL it is not dropped completely, it just
3959 * undergoes a different calculation.
3961 TRACE("Vertex got clipped\n");
3968 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3969 * outside of the main vertex buffer memory. That needs some more
3974 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3977 ( (float *) dest_ptr)[0] = x;
3978 ( (float *) dest_ptr)[1] = y;
3979 ( (float *) dest_ptr)[2] = z;
3980 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3982 dest_ptr += 3 * sizeof(float);
3984 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3985 dest_ptr += sizeof(float);
3990 ( (float *) dest_conv)[0] = x * w;
3991 ( (float *) dest_conv)[1] = y * w;
3992 ( (float *) dest_conv)[2] = z * w;
3993 ( (float *) dest_conv)[3] = w;
3995 dest_conv += 3 * sizeof(float);
3997 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3998 dest_conv += sizeof(float);
4002 if (DestFVF & WINED3DFVF_PSIZE) {
4003 dest_ptr += sizeof(DWORD);
4004 if(dest_conv) dest_conv += sizeof(DWORD);
4006 if (DestFVF & WINED3DFVF_NORMAL) {
4007 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
4008 const float *normal = (const float *)(element->data + i * element->stride);
4009 /* AFAIK this should go into the lighting information */
4010 FIXME("Didn't expect the destination to have a normal\n");
4011 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4013 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4017 if (DestFVF & WINED3DFVF_DIFFUSE) {
4018 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
4019 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
4020 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
4022 static BOOL warned = FALSE;
4025 ERR("No diffuse color in source, but destination has one\n");
4029 *( (DWORD *) dest_ptr) = 0xffffffff;
4030 dest_ptr += sizeof(DWORD);
4033 *( (DWORD *) dest_conv) = 0xffffffff;
4034 dest_conv += sizeof(DWORD);
4038 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4040 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4041 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4042 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4043 dest_conv += sizeof(DWORD);
4048 if (DestFVF & WINED3DFVF_SPECULAR)
4050 /* What's the color value in the feedback buffer? */
4051 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
4052 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
4053 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
4055 static BOOL warned = FALSE;
4058 ERR("No specular color in source, but destination has one\n");
4062 *( (DWORD *) dest_ptr) = 0xFF000000;
4063 dest_ptr += sizeof(DWORD);
4066 *( (DWORD *) dest_conv) = 0xFF000000;
4067 dest_conv += sizeof(DWORD);
4071 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4073 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4074 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4075 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4076 dest_conv += sizeof(DWORD);
4081 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4082 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
4083 const float *tex_coord = (const float *)(element->data + i * element->stride);
4084 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
4086 ERR("No source texture, but destination requests one\n");
4087 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4088 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4091 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4093 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4100 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
4101 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4102 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4103 dwCount * get_flexible_vertex_size(DestFVF),
4105 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4106 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4113 #undef copy_and_next
4115 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
4116 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
4119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4120 struct wined3d_stream_info stream_info;
4121 const struct wined3d_gl_info *gl_info;
4122 struct wined3d_context *context;
4123 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4126 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4129 ERR("Output vertex declaration not implemented yet\n");
4132 /* Need any context to write to the vbo. */
4133 context = context_acquire(This, NULL);
4134 gl_info = context->gl_info;
4136 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4137 * control the streamIsUP flag, thus restore it afterwards.
4139 This->stateBlock->streamIsUP = FALSE;
4140 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
4141 This->stateBlock->streamIsUP = streamWasUP;
4143 if(vbo || SrcStartIndex) {
4145 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4146 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
4148 * Also get the start index in, but only loop over all elements if there's something to add at all.
4150 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
4152 struct wined3d_stream_info_element *e;
4154 if (!(stream_info.use_map & (1 << i))) continue;
4156 e = &stream_info.elements[i];
4157 if (e->buffer_object)
4159 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
4160 e->buffer_object = 0;
4161 e->data = (BYTE *)((ULONG_PTR)e->data + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
4163 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
4164 vb->buffer_object = 0;
4167 if (e->data) e->data += e->stride * SrcStartIndex;
4171 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
4172 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
4174 context_release(context);
4180 * Get / Set Texture Stage States
4181 * TODO: Verify against dx9 definitions
4183 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4184 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4185 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4186 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4188 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4190 if (Stage >= gl_info->limits.texture_stages)
4192 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
4193 Stage, gl_info->limits.texture_stages - 1);
4197 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4198 This->updateStateBlock->textureState[Stage][Type] = Value;
4200 if (This->isRecordingState) {
4201 TRACE("Recording... not performing anything\n");
4205 /* Checked after the assignments to allow proper stateblock recording */
4206 if(oldValue == Value) {
4207 TRACE("App is setting the old value over, nothing to do\n");
4211 if(Stage > This->stateBlock->lowest_disabled_stage &&
4212 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4213 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4214 * Changes in other states are important on disabled stages too
4219 if(Type == WINED3DTSS_COLOROP) {
4222 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4223 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4224 * they have to be disabled
4226 * The current stage is dirtified below.
4228 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4229 TRACE("Additionally dirtifying stage %u\n", i);
4230 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4232 This->stateBlock->lowest_disabled_stage = Stage;
4233 TRACE("New lowest disabled: %u\n", Stage);
4234 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4235 /* Previously disabled stage enabled. Stages above it may need enabling
4236 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4237 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4239 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4242 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4244 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4247 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4248 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4250 This->stateBlock->lowest_disabled_stage = i;
4251 TRACE("New lowest disabled: %u\n", i);
4255 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4260 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4261 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4262 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4263 *pValue = This->updateStateBlock->textureState[Stage][Type];
4270 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4271 DWORD stage, IWineD3DBaseTexture *texture)
4273 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4274 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4275 IWineD3DBaseTexture *prev;
4277 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4279 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4280 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4282 /* Windows accepts overflowing this array... we do not. */
4283 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
4285 WARN("Ignoring invalid stage %u.\n", stage);
4289 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4290 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4292 WARN("Rejecting attempt to set scratch texture.\n");
4293 return WINED3DERR_INVALIDCALL;
4296 This->updateStateBlock->changed.textures |= 1 << stage;
4298 prev = This->updateStateBlock->textures[stage];
4299 TRACE("Previous texture %p.\n", prev);
4301 if (texture == prev)
4303 TRACE("App is setting the same texture again, nothing to do.\n");
4307 TRACE("Setting new texture to %p.\n", texture);
4308 This->updateStateBlock->textures[stage] = texture;
4310 if (This->isRecordingState)
4312 TRACE("Recording... not performing anything\n");
4314 if (texture) IWineD3DBaseTexture_AddRef(texture);
4315 if (prev) IWineD3DBaseTexture_Release(prev);
4322 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4323 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4324 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
4326 IWineD3DBaseTexture_AddRef(texture);
4328 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
4330 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4333 if (!prev && stage < gl_info->limits.texture_stages)
4335 /* The source arguments for color and alpha ops have different
4336 * meanings when a NULL texture is bound, so the COLOROP and
4337 * ALPHAOP have to be dirtified. */
4338 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4339 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4342 if (bind_count == 1) t->baseTexture.sampler = stage;
4347 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4348 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4350 IWineD3DBaseTexture_Release(prev);
4352 if (!texture && stage < gl_info->limits.texture_stages)
4354 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4355 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4358 if (bind_count && t->baseTexture.sampler == stage)
4362 /* Search for other stages the texture is bound to. Shouldn't
4363 * happen if applications bind textures to a single stage only. */
4364 TRACE("Searching for other stages the texture is bound to.\n");
4365 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4367 if (This->updateStateBlock->textures[i] == prev)
4369 TRACE("Texture is also bound to stage %u.\n", i);
4370 t->baseTexture.sampler = i;
4377 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4382 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4383 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4385 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4387 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4388 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4391 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4392 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4393 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4396 *ppTexture=This->stateBlock->textures[Stage];
4398 IWineD3DBaseTexture_AddRef(*ppTexture);
4400 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4408 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4409 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4411 IWineD3DSwapChain *swapchain;
4414 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4415 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4417 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4420 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4424 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4425 IWineD3DSwapChain_Release(swapchain);
4428 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4435 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4437 WARN("(%p) : stub, calling idirect3d for now\n", This);
4438 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4441 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4442 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4443 IWineD3DSwapChain *swapChain;
4446 if(iSwapChain > 0) {
4447 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4448 if (hr == WINED3D_OK) {
4449 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4450 IWineD3DSwapChain_Release(swapChain);
4452 FIXME("(%p) Error getting display mode\n", This);
4455 /* Don't read the real display mode,
4456 but return the stored mode instead. X11 can't change the color
4457 depth, and some apps are pretty angry if they SetDisplayMode from
4458 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4460 Also don't relay to the swapchain because with ddraw it's possible
4461 that there isn't a swapchain at all */
4462 pMode->Width = This->ddraw_width;
4463 pMode->Height = This->ddraw_height;
4464 pMode->Format = This->ddraw_format;
4465 pMode->RefreshRate = 0;
4473 * Stateblock related functions
4476 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4477 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4478 IWineD3DStateBlock *stateblock;
4481 TRACE("(%p)\n", This);
4483 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4485 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock);
4486 if (FAILED(hr)) return hr;
4488 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4489 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4490 This->isRecordingState = TRUE;
4492 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4497 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4498 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4499 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4501 if (!This->isRecordingState) {
4502 WARN("(%p) not recording! returning error\n", This);
4503 *ppStateBlock = NULL;
4504 return WINED3DERR_INVALIDCALL;
4507 stateblock_init_contained_states(object);
4509 *ppStateBlock = (IWineD3DStateBlock*) object;
4510 This->isRecordingState = FALSE;
4511 This->updateStateBlock = This->stateBlock;
4512 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4513 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4514 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4519 * Scene related functions
4521 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4522 /* At the moment we have no need for any functionality at the beginning
4524 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4525 TRACE("(%p)\n", This);
4528 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4529 return WINED3DERR_INVALIDCALL;
4531 This->inScene = TRUE;
4535 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4537 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4538 struct wined3d_context *context;
4540 TRACE("(%p)\n", This);
4542 if(!This->inScene) {
4543 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4544 return WINED3DERR_INVALIDCALL;
4547 context = context_acquire(This, NULL);
4548 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4550 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4552 context_release(context);
4554 This->inScene = FALSE;
4558 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4559 const RECT *pSourceRect, const RECT *pDestRect,
4560 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4562 IWineD3DSwapChain *swapChain = NULL;
4564 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4566 TRACE("iface %p.\n", iface);
4568 for(i = 0 ; i < swapchains ; i ++) {
4570 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4571 TRACE("Presenting chain %d, %p.\n", i, swapChain);
4572 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4573 IWineD3DSwapChain_Release(swapChain);
4579 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count,
4580 const WINED3DRECT *pRects, DWORD Flags, WINED3DCOLOR color, float Z, DWORD Stencil)
4582 const WINED3DCOLORVALUE c = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
4583 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4586 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), color (0x%08x), Z (%f), Stencil (%d)\n", This,
4587 Count, pRects, Flags, color, Z, Stencil);
4589 if (Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && !This->depth_stencil)
4591 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4592 /* TODO: What about depth stencil buffers without stencil bits? */
4593 return WINED3DERR_INVALIDCALL;
4596 device_get_draw_rect(This, &draw_rect);
4598 return device_clear_render_targets(This, This->adapter->gl_info.limits.buffers,
4599 This->render_targets, Count, (const RECT *)pRects, &draw_rect, Flags,
4607 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4608 WINED3DPRIMITIVETYPE primitive_type)
4610 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4612 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4614 This->updateStateBlock->changed.primitive_type = TRUE;
4615 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4618 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4619 WINED3DPRIMITIVETYPE *primitive_type)
4621 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4623 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4625 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4627 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4630 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4632 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4634 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4636 if(!This->stateBlock->vertexDecl) {
4637 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4638 return WINED3DERR_INVALIDCALL;
4641 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4642 if(This->stateBlock->streamIsUP) {
4643 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4644 This->stateBlock->streamIsUP = FALSE;
4647 if(This->stateBlock->loadBaseVertexIndex != 0) {
4648 This->stateBlock->loadBaseVertexIndex = 0;
4649 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4651 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4652 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4656 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4658 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4660 IWineD3DBuffer *pIB;
4663 pIB = This->stateBlock->pIndexData;
4665 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4666 * without an index buffer set. (The first time at least...)
4667 * D3D8 simply dies, but I doubt it can do much harm to return
4668 * D3DERR_INVALIDCALL there as well. */
4669 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4670 return WINED3DERR_INVALIDCALL;
4673 if(!This->stateBlock->vertexDecl) {
4674 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4675 return WINED3DERR_INVALIDCALL;
4678 if(This->stateBlock->streamIsUP) {
4679 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4680 This->stateBlock->streamIsUP = FALSE;
4682 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4684 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4686 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4692 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4693 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4694 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4697 drawPrimitive(iface, index_count, startIndex, idxStride,
4698 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4703 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4704 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4706 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4709 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4710 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4712 if(!This->stateBlock->vertexDecl) {
4713 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4714 return WINED3DERR_INVALIDCALL;
4717 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4718 vb = This->stateBlock->streamSource[0];
4719 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4720 if (vb) IWineD3DBuffer_Release(vb);
4721 This->stateBlock->streamOffset[0] = 0;
4722 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4723 This->stateBlock->streamIsUP = TRUE;
4724 This->stateBlock->loadBaseVertexIndex = 0;
4726 /* TODO: Only mark dirty if drawing from a different UP address */
4727 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4729 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4731 /* MSDN specifies stream zero settings must be set to NULL */
4732 This->stateBlock->streamStride[0] = 0;
4733 This->stateBlock->streamSource[0] = NULL;
4735 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4736 * the new stream sources or use UP drawing again
4741 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4742 UINT index_count, const void *pIndexData, enum wined3d_format_id IndexDataFormat,
4743 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4746 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4750 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4751 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4753 if(!This->stateBlock->vertexDecl) {
4754 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4755 return WINED3DERR_INVALIDCALL;
4758 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4764 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4765 vb = This->stateBlock->streamSource[0];
4766 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4767 if (vb) IWineD3DBuffer_Release(vb);
4768 This->stateBlock->streamIsUP = TRUE;
4769 This->stateBlock->streamOffset[0] = 0;
4770 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4772 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4773 This->stateBlock->baseVertexIndex = 0;
4774 This->stateBlock->loadBaseVertexIndex = 0;
4775 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4776 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4777 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4779 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4781 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4782 This->stateBlock->streamSource[0] = NULL;
4783 This->stateBlock->streamStride[0] = 0;
4784 ib = This->stateBlock->pIndexData;
4786 IWineD3DBuffer_Release(ib);
4787 This->stateBlock->pIndexData = NULL;
4789 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4790 * SetStreamSource to specify a vertex buffer
4796 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4797 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4801 /* Mark the state dirty until we have nicer tracking
4802 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4805 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4806 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4807 This->stateBlock->baseVertexIndex = 0;
4808 This->up_strided = DrawPrimStrideData;
4809 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4810 This->up_strided = NULL;
4814 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4815 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4816 UINT NumVertices, const void *pIndexData, enum wined3d_format_id IndexDataFormat)
4818 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4819 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4821 /* Mark the state dirty until we have nicer tracking
4822 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4825 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4826 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4827 This->stateBlock->streamIsUP = TRUE;
4828 This->stateBlock->baseVertexIndex = 0;
4829 This->up_strided = DrawPrimStrideData;
4830 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4831 This->up_strided = NULL;
4835 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4836 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4837 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4839 WINED3DLOCKED_BOX src;
4840 WINED3DLOCKED_BOX dst;
4843 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4844 iface, pSourceVolume, pDestinationVolume);
4846 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4847 * dirtification to improve loading performance.
4849 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4850 if(FAILED(hr)) return hr;
4851 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4853 IWineD3DVolume_UnlockBox(pSourceVolume);
4857 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4859 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4861 IWineD3DVolume_UnlockBox(pSourceVolume);
4863 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4868 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4869 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4871 unsigned int level_count, i;
4872 WINED3DRESOURCETYPE type;
4875 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4877 /* Verify that the source and destination textures are non-NULL. */
4878 if (!src_texture || !dst_texture)
4880 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4881 return WINED3DERR_INVALIDCALL;
4884 if (src_texture == dst_texture)
4886 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4887 return WINED3DERR_INVALIDCALL;
4890 /* Verify that the source and destination textures are the same type. */
4891 type = IWineD3DBaseTexture_GetType(src_texture);
4892 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4894 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4895 return WINED3DERR_INVALIDCALL;
4898 /* Check that both textures have the identical numbers of levels. */
4899 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4900 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4902 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4903 return WINED3DERR_INVALIDCALL;
4906 /* Make sure that the destination texture is loaded. */
4907 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4909 /* Update every surface level of the texture. */
4912 case WINED3DRTYPE_TEXTURE:
4914 IWineD3DSurface *src_surface;
4915 IWineD3DSurface *dst_surface;
4917 for (i = 0; i < level_count; ++i)
4919 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4920 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4921 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4922 IWineD3DSurface_Release(dst_surface);
4923 IWineD3DSurface_Release(src_surface);
4926 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4933 case WINED3DRTYPE_CUBETEXTURE:
4935 IWineD3DSurface *src_surface;
4936 IWineD3DSurface *dst_surface;
4937 WINED3DCUBEMAP_FACES face;
4939 for (i = 0; i < level_count; ++i)
4941 /* Update each cube face. */
4942 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4944 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
4945 face, i, &src_surface);
4946 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4947 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
4948 face, i, &dst_surface);
4949 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4950 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4951 IWineD3DSurface_Release(dst_surface);
4952 IWineD3DSurface_Release(src_surface);
4955 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4963 case WINED3DRTYPE_VOLUMETEXTURE:
4965 IWineD3DVolume *src_volume;
4966 IWineD3DVolume *dst_volume;
4968 for (i = 0; i < level_count; ++i)
4970 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
4971 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
4972 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
4973 IWineD3DVolume_Release(dst_volume);
4974 IWineD3DVolume_Release(src_volume);
4977 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
4985 FIXME("Unsupported texture type %#x.\n", type);
4986 return WINED3DERR_INVALIDCALL;
4992 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,
4993 UINT swapchain_idx, IWineD3DSurface *dst_surface)
4995 IWineD3DSwapChain *swapchain;
4998 TRACE("iface %p, swapchain_idx %u, dst_surface %p.\n", iface, swapchain_idx, dst_surface);
5000 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5001 if (FAILED(hr)) return hr;
5003 hr = IWineD3DSwapChain_GetFrontBufferData(swapchain, dst_surface);
5004 IWineD3DSwapChain_Release(swapchain);
5009 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5011 IWineD3DBaseTextureImpl *texture;
5014 TRACE("(%p) : %p\n", This, pNumPasses);
5016 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5017 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5018 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5019 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5021 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5022 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5023 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5026 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5027 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5029 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5030 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5033 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5034 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5037 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5038 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5039 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5044 /* return a sensible default */
5047 TRACE("returning D3D_OK\n");
5051 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5055 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5057 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5058 if (texture && (texture->resource.format_desc->id == WINED3DFMT_P8_UINT
5059 || texture->resource.format_desc->id == WINED3DFMT_P8_UINT_A8_UNORM))
5061 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5066 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5067 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5070 PALETTEENTRY **palettes;
5072 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5074 if (PaletteNumber >= MAX_PALETTES) {
5075 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5076 return WINED3DERR_INVALIDCALL;
5079 if (PaletteNumber >= This->NumberOfPalettes) {
5080 NewSize = This->NumberOfPalettes;
5083 } while(PaletteNumber >= NewSize);
5084 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5086 ERR("Out of memory!\n");
5087 return E_OUTOFMEMORY;
5089 This->palettes = palettes;
5090 This->NumberOfPalettes = NewSize;
5093 if (!This->palettes[PaletteNumber]) {
5094 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5095 if (!This->palettes[PaletteNumber]) {
5096 ERR("Out of memory!\n");
5097 return E_OUTOFMEMORY;
5101 for (j = 0; j < 256; ++j) {
5102 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5103 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5104 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5105 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5107 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5108 TRACE("(%p) : returning\n", This);
5112 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5113 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5115 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5116 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5117 /* What happens in such situation isn't documented; Native seems to silently abort
5118 on such conditions. Return Invalid Call. */
5119 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5120 return WINED3DERR_INVALIDCALL;
5122 for (j = 0; j < 256; ++j) {
5123 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5124 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5125 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5126 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5128 TRACE("(%p) : returning\n", This);
5132 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5133 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5134 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5135 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5136 (tested with reference rasterizer). Return Invalid Call. */
5137 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5138 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5139 return WINED3DERR_INVALIDCALL;
5141 /*TODO: stateblocks */
5142 if (This->currentPalette != PaletteNumber) {
5143 This->currentPalette = PaletteNumber;
5144 dirtify_p8_texture_samplers(This);
5146 TRACE("(%p) : returning\n", This);
5150 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5152 if (PaletteNumber == NULL) {
5153 WARN("(%p) : returning Invalid Call\n", This);
5154 return WINED3DERR_INVALIDCALL;
5156 /*TODO: stateblocks */
5157 *PaletteNumber = This->currentPalette;
5158 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5162 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5163 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5167 FIXME("(%p) : stub\n", This);
5171 This->softwareVertexProcessing = bSoftware;
5176 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5177 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5181 FIXME("(%p) : stub\n", This);
5184 return This->softwareVertexProcessing;
5187 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5188 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5190 IWineD3DSwapChain *swapchain;
5193 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5194 iface, swapchain_idx, raster_status);
5196 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5199 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5203 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5204 IWineD3DSwapChain_Release(swapchain);
5207 WARN("Failed to get raster status, hr %#x.\n", hr);
5214 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5217 if(nSegments != 0.0f) {
5220 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5227 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5232 FIXME("iface %p stub!\n", iface);
5238 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5239 IWineD3DSurface *src_surface, const RECT *src_rect,
5240 IWineD3DSurface *dst_surface, const POINT *dst_point)
5242 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5243 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5244 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5245 const struct wined3d_format_desc *src_format;
5246 const struct wined3d_format_desc *dst_format;
5247 const struct wined3d_gl_info *gl_info;
5248 struct wined3d_context *context;
5249 const unsigned char *data;
5250 UINT update_w, update_h;
5251 CONVERT_TYPES convert;
5255 struct wined3d_format_desc desc;
5257 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5258 iface, src_surface, wine_dbgstr_rect(src_rect),
5259 dst_surface, wine_dbgstr_point(dst_point));
5261 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5263 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5264 src_surface, dst_surface);
5265 return WINED3DERR_INVALIDCALL;
5268 src_format = src_impl->resource.format_desc;
5269 dst_format = dst_impl->resource.format_desc;
5271 if (src_format->id != dst_format->id)
5273 WARN("Source and destination surfaces should have the same format.\n");
5274 return WINED3DERR_INVALIDCALL;
5277 dst_x = dst_point ? dst_point->x : 0;
5278 dst_y = dst_point ? dst_point->y : 0;
5280 /* This call loads the OpenGL surface directly, instead of copying the
5281 * surface to the destination's sysmem copy. If surface conversion is
5282 * needed, use BltFast instead to copy in sysmem and use regular surface
5284 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &desc, &convert);
5285 if (convert != NO_CONVERSION || desc.convert)
5286 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5288 context = context_acquire(This, NULL);
5289 gl_info = context->gl_info;
5292 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5293 checkGLcall("glActiveTextureARB");
5296 /* Make sure the surface is loaded and up to date */
5297 surface_internal_preload(dst_impl, SRGB_RGB);
5298 IWineD3DSurface_BindTexture(dst_surface, FALSE);
5300 src_w = src_impl->currentDesc.Width;
5301 src_h = src_impl->currentDesc.Height;
5302 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5303 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5305 data = IWineD3DSurface_GetData(src_surface);
5306 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5310 if (dst_format->Flags & WINED3DFMT_FLAG_COMPRESSED)
5312 UINT row_length = wined3d_format_calculate_size(src_format, 1, update_w, 1);
5313 UINT row_count = (update_h + src_format->block_height - 1) / src_format->block_height;
5314 UINT src_pitch = wined3d_format_calculate_size(src_format, 1, src_w, 1);
5318 data += (src_rect->top / src_format->block_height) * src_pitch;
5319 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5322 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5323 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5324 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5326 if (row_length == src_pitch)
5328 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5329 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5335 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5336 * can't use the unpack row length like below. */
5337 for (row = 0, y = dst_y; row < row_count; ++row)
5339 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5340 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5341 y += src_format->block_height;
5345 checkGLcall("glCompressedTexSubImage2DARB");
5351 data += src_rect->top * src_w * src_format->byte_count;
5352 data += src_rect->left * src_format->byte_count;
5355 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5356 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5357 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5359 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5360 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5361 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5362 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5363 checkGLcall("glTexSubImage2D");
5367 context_release(context);
5369 surface_modify_location(dst_impl, SFLAG_INTEXTURE, TRUE);
5370 sampler = This->rev_tex_unit_map[0];
5371 if (sampler != WINED3D_UNMAPPED_STAGE)
5373 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5379 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5380 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5381 struct WineD3DRectPatch *patch;
5382 GLenum old_primitive_type;
5386 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5388 if(!(Handle || pRectPatchInfo)) {
5389 /* TODO: Write a test for the return value, thus the FIXME */
5390 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5391 return WINED3DERR_INVALIDCALL;
5395 i = PATCHMAP_HASHFUNC(Handle);
5397 LIST_FOR_EACH(e, &This->patches[i]) {
5398 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5399 if(patch->Handle == Handle) {
5406 TRACE("Patch does not exist. Creating a new one\n");
5407 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5408 patch->Handle = Handle;
5409 list_add_head(&This->patches[i], &patch->entry);
5411 TRACE("Found existing patch %p\n", patch);
5414 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5415 * attributes we have to tesselate, read back, and draw. This needs a patch
5416 * management structure instance. Create one.
5418 * A possible improvement is to check if a vertex shader is used, and if not directly
5421 FIXME("Drawing an uncached patch. This is slow\n");
5422 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5425 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5426 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5427 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5429 TRACE("Tesselation density or patch info changed, retesselating\n");
5431 if(pRectPatchInfo) {
5432 patch->RectPatchInfo = *pRectPatchInfo;
5434 patch->numSegs[0] = pNumSegs[0];
5435 patch->numSegs[1] = pNumSegs[1];
5436 patch->numSegs[2] = pNumSegs[2];
5437 patch->numSegs[3] = pNumSegs[3];
5439 hr = tesselate_rectpatch(This, patch);
5441 WARN("Patch tesselation failed\n");
5443 /* Do not release the handle to store the params of the patch */
5445 HeapFree(GetProcessHeap(), 0, patch);
5451 This->currentPatch = patch;
5452 old_primitive_type = This->stateBlock->gl_primitive_type;
5453 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5454 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5455 This->stateBlock->gl_primitive_type = old_primitive_type;
5456 This->currentPatch = NULL;
5458 /* Destroy uncached patches */
5460 HeapFree(GetProcessHeap(), 0, patch->mem);
5461 HeapFree(GetProcessHeap(), 0, patch);
5466 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5467 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5469 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5470 iface, handle, segment_count, patch_info);
5475 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5476 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5478 struct WineD3DRectPatch *patch;
5480 TRACE("(%p) Handle(%d)\n", This, Handle);
5482 i = PATCHMAP_HASHFUNC(Handle);
5483 LIST_FOR_EACH(e, &This->patches[i]) {
5484 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5485 if(patch->Handle == Handle) {
5486 TRACE("Deleting patch %p\n", patch);
5487 list_remove(&patch->entry);
5488 HeapFree(GetProcessHeap(), 0, patch->mem);
5489 HeapFree(GetProcessHeap(), 0, patch);
5494 /* TODO: Write a test for the return value */
5495 FIXME("Attempt to destroy nonexistent patch\n");
5496 return WINED3DERR_INVALIDCALL;
5499 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5500 IWineD3DSurface *surface, const WINED3DRECT *pRect, const WINED3DCOLORVALUE *color)
5502 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)surface;
5505 TRACE("iface %p, surface %p, rect %s, color {%.8e, %.8e, %.8e, %.8e}.\n",
5506 iface, surface, wine_dbgstr_rect((const RECT *)pRect),
5507 color->r, color->g, color->b, color->a);
5509 if (s->resource.pool != WINED3DPOOL_DEFAULT && s->resource.pool != WINED3DPOOL_SYSTEMMEM)
5511 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5512 return WINED3DERR_INVALIDCALL;
5515 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5517 const RECT draw_rect = {0, 0, s->currentDesc.Width, s->currentDesc.Height};
5519 return device_clear_render_targets((IWineD3DDeviceImpl *)iface, 1, &s,
5520 !!pRect, (const RECT *)pRect, &draw_rect, WINED3DCLEAR_TARGET, color, 0.0f, 0);
5524 /* Just forward this to the DirectDraw blitting engine */
5525 memset(&BltFx, 0, sizeof(BltFx));
5526 BltFx.dwSize = sizeof(BltFx);
5527 BltFx.u5.dwFillColor = wined3d_format_convert_from_float(s->resource.format_desc, color);
5528 return IWineD3DSurface_Blt(surface, (const RECT *)pRect, NULL, NULL,
5529 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5533 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5534 IWineD3DRendertargetView *rendertarget_view, const WINED3DCOLORVALUE *color)
5536 IWineD3DResource *resource;
5537 IWineD3DSurfaceImpl *surface;
5540 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5543 ERR("Failed to get resource, hr %#x\n", hr);
5547 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5549 FIXME("Only supported on surface resources\n");
5550 IWineD3DResource_Release(resource);
5554 surface = (IWineD3DSurfaceImpl *)resource;
5556 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5558 const RECT draw_rect = {0, 0, surface->currentDesc.Width, surface->currentDesc.Height};
5560 device_clear_render_targets((IWineD3DDeviceImpl *)iface, 1, &surface,
5561 0, NULL, &draw_rect, WINED3DCLEAR_TARGET, color, 0.0f, 0);
5567 /* Just forward this to the DirectDraw blitting engine */
5568 memset(&BltFx, 0, sizeof(BltFx));
5569 BltFx.dwSize = sizeof(BltFx);
5570 BltFx.u5.dwFillColor = wined3d_format_convert_from_float(surface->resource.format_desc, color);
5571 hr = IWineD3DSurface_Blt((IWineD3DSurface *)surface, NULL, NULL, NULL,
5572 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5575 ERR("Blt failed, hr %#x\n", hr);
5579 IWineD3DResource_Release(resource);
5582 /* rendertarget and depth stencil functions */
5583 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice *iface,
5584 DWORD render_target_idx, IWineD3DSurface **render_target)
5586 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5588 TRACE("iface %p, render_target_idx %u, render_target %p.\n",
5589 iface, render_target_idx, render_target);
5591 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5593 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5594 return WINED3DERR_INVALIDCALL;
5597 *render_target = (IWineD3DSurface *)device->render_targets[render_target_idx];
5598 if (*render_target) IWineD3DSurface_AddRef(*render_target);
5600 TRACE("Returning render target %p.\n", *render_target);
5605 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5606 IWineD3DSurface *front, IWineD3DSurface *back)
5608 IWineD3DSurfaceImpl *front_impl = (IWineD3DSurfaceImpl *)front;
5609 IWineD3DSurfaceImpl *back_impl = (IWineD3DSurfaceImpl *)back;
5610 IWineD3DSwapChainImpl *swapchain;
5613 TRACE("iface %p, front %p, back %p.\n", iface, front, back);
5615 if (FAILED(hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&swapchain)))
5617 ERR("Failed to get the swapchain, hr %#x.\n", hr);
5621 if (front_impl && !(front_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5623 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5624 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5625 return WINED3DERR_INVALIDCALL;
5630 if (!(back_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5632 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5633 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5634 return WINED3DERR_INVALIDCALL;
5637 if (!swapchain->back_buffers)
5639 swapchain->back_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*swapchain->back_buffers));
5640 if (!swapchain->back_buffers)
5642 ERR("Failed to allocate back buffer array memory.\n");
5643 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5644 return E_OUTOFMEMORY;
5649 if (swapchain->front_buffer != front_impl)
5651 TRACE("Changing the front buffer from %p to %p.\n", swapchain->front_buffer, front_impl);
5653 if (swapchain->front_buffer)
5654 surface_set_container(swapchain->front_buffer, WINED3D_CONTAINER_NONE, NULL);
5655 swapchain->front_buffer = front_impl;
5658 surface_set_container(front_impl, WINED3D_CONTAINER_SWAPCHAIN, (IWineD3DBase *)swapchain);
5661 if (swapchain->back_buffers[0] != back_impl)
5663 TRACE("Changing the back buffer from %p to %p.\n", swapchain->back_buffers[0], back_impl);
5665 if (swapchain->back_buffers[0])
5666 surface_set_container(swapchain->back_buffers[0], WINED3D_CONTAINER_NONE, NULL);
5667 swapchain->back_buffers[0] = back_impl;
5671 swapchain->presentParms.BackBufferWidth = back_impl->currentDesc.Width;
5672 swapchain->presentParms.BackBufferHeight = back_impl->currentDesc.Height;
5673 swapchain->presentParms.BackBufferFormat = back_impl->resource.format_desc->id;
5674 swapchain->presentParms.BackBufferCount = 1;
5676 surface_set_container(back_impl, WINED3D_CONTAINER_SWAPCHAIN, (IWineD3DBase *)swapchain);
5680 swapchain->presentParms.BackBufferCount = 0;
5681 HeapFree(GetProcessHeap(), 0, swapchain->back_buffers);
5682 swapchain->back_buffers = NULL;
5686 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5690 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface **depth_stencil)
5692 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5694 TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
5696 *depth_stencil = (IWineD3DSurface *)device->depth_stencil;
5697 TRACE("Returning depth/stencil surface %p.\n", *depth_stencil);
5698 if (!*depth_stencil) return WINED3DERR_NOTFOUND;
5699 IWineD3DSurface_AddRef(*depth_stencil);
5704 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface,
5705 DWORD render_target_idx, IWineD3DSurface *render_target, BOOL set_viewport)
5707 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
5708 IWineD3DSurfaceImpl *prev;
5710 TRACE("iface %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
5711 iface, render_target_idx, render_target, set_viewport);
5713 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
5715 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
5716 return WINED3DERR_INVALIDCALL;
5719 prev = device->render_targets[render_target_idx];
5720 if (render_target == (IWineD3DSurface *)prev)
5722 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5726 /* Render target 0 can't be set to NULL. */
5727 if (!render_target && !render_target_idx)
5729 WARN("Trying to set render target 0 to NULL.\n");
5730 return WINED3DERR_INVALIDCALL;
5733 if (render_target && !(((IWineD3DSurfaceImpl *)render_target)->resource.usage & WINED3DUSAGE_RENDERTARGET))
5735 FIXME("Surface %p doesn't have render target usage.\n", render_target);
5736 return WINED3DERR_INVALIDCALL;
5739 if (render_target) IWineD3DSurface_AddRef(render_target);
5740 device->render_targets[render_target_idx] = (IWineD3DSurfaceImpl *)render_target;
5741 /* Release after the assignment, to prevent device_resource_released()
5742 * from seeing the surface as still in use. */
5743 if (prev) IWineD3DSurface_Release((IWineD3DSurface *)prev);
5745 /* Render target 0 is special. */
5746 if (!render_target_idx && set_viewport)
5748 /* Set the viewport and scissor rectangles, if requested. Tests show
5749 * that stateblock recording is ignored, the change goes directly
5750 * into the primary stateblock. */
5751 device->stateBlock->viewport.Height = device->render_targets[0]->currentDesc.Height;
5752 device->stateBlock->viewport.Width = device->render_targets[0]->currentDesc.Width;
5753 device->stateBlock->viewport.X = 0;
5754 device->stateBlock->viewport.Y = 0;
5755 device->stateBlock->viewport.MaxZ = 1.0f;
5756 device->stateBlock->viewport.MinZ = 0.0f;
5757 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_VIEWPORT);
5759 device->stateBlock->scissorRect.top = 0;
5760 device->stateBlock->scissorRect.left = 0;
5761 device->stateBlock->scissorRect.right = device->stateBlock->viewport.Width;
5762 device->stateBlock->scissorRect.bottom = device->stateBlock->viewport.Height;
5763 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SCISSORRECT);
5769 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil)
5771 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5772 IWineD3DSurfaceImpl *tmp;
5774 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, depth_stencil, This->depth_stencil);
5776 if (This->depth_stencil == (IWineD3DSurfaceImpl *)depth_stencil)
5778 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5782 if (This->depth_stencil)
5784 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5785 || This->depth_stencil->Flags & SFLAG_DISCARD)
5787 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5788 This->depth_stencil->currentDesc.Width,
5789 This->depth_stencil->currentDesc.Height);
5790 if (This->depth_stencil == This->onscreen_depth_stencil)
5792 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5793 This->onscreen_depth_stencil = NULL;
5798 tmp = This->depth_stencil;
5799 This->depth_stencil = (IWineD3DSurfaceImpl *)depth_stencil;
5800 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5801 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5803 if ((!tmp && depth_stencil) || (!depth_stencil && tmp))
5805 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5806 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5807 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5808 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5814 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice *iface,
5815 UINT XHotSpot, UINT YHotSpot, IWineD3DSurface *cursor_image)
5817 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5818 IWineD3DSurfaceImpl *s = (IWineD3DSurfaceImpl *)cursor_image;
5819 WINED3DLOCKED_RECT lockedRect;
5821 TRACE("iface %p, hotspot_x %u, hotspot_y %u, cursor_image %p.\n",
5822 iface, XHotSpot, YHotSpot, cursor_image);
5824 /* some basic validation checks */
5825 if (This->cursorTexture)
5827 struct wined3d_context *context = context_acquire(This, NULL);
5829 glDeleteTextures(1, &This->cursorTexture);
5831 context_release(context);
5832 This->cursorTexture = 0;
5835 if ((s->currentDesc.Width == 32) && (s->currentDesc.Height == 32))
5836 This->haveHardwareCursor = TRUE;
5838 This->haveHardwareCursor = FALSE;
5842 WINED3DLOCKED_RECT rect;
5844 /* MSDN: Cursor must be A8R8G8B8 */
5845 if (s->resource.format_desc->id != WINED3DFMT_B8G8R8A8_UNORM)
5847 WARN("surface %p has an invalid format.\n", cursor_image);
5848 return WINED3DERR_INVALIDCALL;
5851 /* MSDN: Cursor must be smaller than the display mode */
5852 if (s->currentDesc.Width > This->ddraw_width
5853 || s->currentDesc.Height > This->ddraw_height)
5855 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
5856 s, s->currentDesc.Width, s->currentDesc.Height, This->ddraw_width, This->ddraw_height);
5857 return WINED3DERR_INVALIDCALL;
5860 if (!This->haveHardwareCursor) {
5861 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5863 /* Do not store the surface's pointer because the application may
5864 * release it after setting the cursor image. Windows doesn't
5865 * addref the set surface, so we can't do this either without
5866 * creating circular refcount dependencies. Copy out the gl texture
5869 This->cursorWidth = s->currentDesc.Width;
5870 This->cursorHeight = s->currentDesc.Height;
5871 if (SUCCEEDED(IWineD3DSurface_LockRect(cursor_image, &rect, NULL, WINED3DLOCK_READONLY)))
5873 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
5874 const struct wined3d_format_desc *format_desc = getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, gl_info);
5875 struct wined3d_context *context;
5876 char *mem, *bits = rect.pBits;
5877 GLint intfmt = format_desc->glInternal;
5878 GLint format = format_desc->glFormat;
5879 GLint type = format_desc->glType;
5880 INT height = This->cursorHeight;
5881 INT width = This->cursorWidth;
5882 INT bpp = format_desc->byte_count;
5886 /* Reformat the texture memory (pitch and width can be
5888 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5889 for(i = 0; i < height; i++)
5890 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5891 IWineD3DSurface_UnlockRect(cursor_image);
5893 context = context_acquire(This, NULL);
5897 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5899 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5900 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5903 /* Make sure that a proper texture unit is selected */
5904 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5905 checkGLcall("glActiveTextureARB");
5906 sampler = This->rev_tex_unit_map[0];
5907 if (sampler != WINED3D_UNMAPPED_STAGE)
5909 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5911 /* Create a new cursor texture */
5912 glGenTextures(1, &This->cursorTexture);
5913 checkGLcall("glGenTextures");
5914 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5915 checkGLcall("glBindTexture");
5916 /* Copy the bitmap memory into the cursor texture */
5917 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
5918 HeapFree(GetProcessHeap(), 0, mem);
5919 checkGLcall("glTexImage2D");
5921 if (gl_info->supported[APPLE_CLIENT_STORAGE])
5923 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5924 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5929 context_release(context);
5933 FIXME("A cursor texture was not returned.\n");
5934 This->cursorTexture = 0;
5939 /* Draw a hardware cursor */
5940 ICONINFO cursorInfo;
5942 /* Create and clear maskBits because it is not needed for
5943 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
5945 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
5946 (s->currentDesc.Width * s->currentDesc.Height / 8));
5947 IWineD3DSurface_LockRect(cursor_image, &lockedRect, NULL,
5948 WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY);
5949 TRACE("width: %u height: %u.\n", s->currentDesc.Width, s->currentDesc.Height);
5951 cursorInfo.fIcon = FALSE;
5952 cursorInfo.xHotspot = XHotSpot;
5953 cursorInfo.yHotspot = YHotSpot;
5954 cursorInfo.hbmMask = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 1, maskBits);
5955 cursorInfo.hbmColor = CreateBitmap(s->currentDesc.Width, s->currentDesc.Height, 1, 32, lockedRect.pBits);
5956 IWineD3DSurface_UnlockRect(cursor_image);
5957 /* Create our cursor and clean up. */
5958 cursor = CreateIconIndirect(&cursorInfo);
5960 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
5961 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
5962 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
5963 This->hardwareCursor = cursor;
5964 HeapFree(GetProcessHeap(), 0, maskBits);
5968 This->xHotSpot = XHotSpot;
5969 This->yHotSpot = YHotSpot;
5973 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5974 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5975 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5977 This->xScreenSpace = XScreenSpace;
5978 This->yScreenSpace = YScreenSpace;
5984 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5985 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5986 BOOL oldVisible = This->bCursorVisible;
5989 TRACE("(%p) : visible(%d)\n", This, bShow);
5992 * When ShowCursor is first called it should make the cursor appear at the OS's last
5993 * known cursor position. Because of this, some applications just repetitively call
5994 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
5997 This->xScreenSpace = pt.x;
5998 This->yScreenSpace = pt.y;
6000 if (This->haveHardwareCursor) {
6001 This->bCursorVisible = bShow;
6003 SetCursor(This->hardwareCursor);
6009 if (This->cursorTexture)
6010 This->bCursorVisible = bShow;
6016 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6017 TRACE("checking resource %p for eviction\n", resource);
6018 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6019 TRACE("Evicting %p\n", resource);
6020 IWineD3DResource_UnLoad(resource);
6022 IWineD3DResource_Release(resource);
6026 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6028 TRACE("iface %p.\n", iface);
6030 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6031 /* Invalidate stream sources, the buffer(s) may have been evicted. */
6032 IWineD3DDeviceImpl_MarkStateDirty((IWineD3DDeviceImpl *)iface, STATE_STREAMSRC);
6037 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6039 IWineD3DDeviceImpl *device = surface->resource.device;
6040 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6042 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6043 if(surface->Flags & SFLAG_DIBSECTION) {
6044 /* Release the DC */
6045 SelectObject(surface->hDC, surface->dib.holdbitmap);
6046 DeleteDC(surface->hDC);
6047 /* Release the DIB section */
6048 DeleteObject(surface->dib.DIBsection);
6049 surface->dib.bitmap_data = NULL;
6050 surface->resource.allocatedMemory = NULL;
6051 surface->Flags &= ~SFLAG_DIBSECTION;
6053 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6054 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6055 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6056 || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
6058 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6059 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6061 surface->pow2Width = surface->pow2Height = 1;
6062 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6063 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6066 if (surface->texture_name)
6068 struct wined3d_context *context = context_acquire(device, NULL);
6070 glDeleteTextures(1, &surface->texture_name);
6072 context_release(context);
6073 surface->texture_name = 0;
6074 surface->Flags &= ~SFLAG_CLIENT;
6076 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6077 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6078 surface->Flags |= SFLAG_NONPOW2;
6080 surface->Flags &= ~SFLAG_NONPOW2;
6082 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6083 surface->resource.allocatedMemory = NULL;
6084 surface->resource.heapMemory = NULL;
6085 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6087 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6089 if (!surface_init_sysmem(surface))
6091 return E_OUTOFMEMORY;
6096 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6097 TRACE("Unloading resource %p\n", resource);
6098 IWineD3DResource_UnLoad(resource);
6099 IWineD3DResource_Release(resource);
6103 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6106 WINED3DDISPLAYMODE m;
6109 /* All Windowed modes are supported, as is leaving the current mode */
6110 if(pp->Windowed) return TRUE;
6111 if(!pp->BackBufferWidth) return TRUE;
6112 if(!pp->BackBufferHeight) return TRUE;
6114 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6115 for(i = 0; i < count; i++) {
6116 memset(&m, 0, sizeof(m));
6117 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6119 ERR("EnumAdapterModes failed\n");
6121 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6122 /* Mode found, it is supported */
6126 /* Mode not found -> not supported */
6130 static void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6133 const struct wined3d_gl_info *gl_info;
6134 struct wined3d_context *context;
6135 IWineD3DBaseShaderImpl *shader;
6137 context = context_acquire(This, NULL);
6138 gl_info = context->gl_info;
6140 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6141 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6142 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6146 if(This->depth_blt_texture) {
6147 glDeleteTextures(1, &This->depth_blt_texture);
6148 This->depth_blt_texture = 0;
6150 if (This->depth_blt_rb) {
6151 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6152 This->depth_blt_rb = 0;
6153 This->depth_blt_rb_w = 0;
6154 This->depth_blt_rb_h = 0;
6158 This->blitter->free_private(iface);
6159 This->frag_pipe->free_private(iface);
6160 This->shader_backend->shader_free_private(iface);
6161 destroy_dummy_textures(This, gl_info);
6163 context_release(context);
6165 while (This->numContexts)
6167 context_destroy(This, This->contexts[0]);
6169 HeapFree(GetProcessHeap(), 0, swapchain->context);
6170 swapchain->context = NULL;
6171 swapchain->num_contexts = 0;
6174 static HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6177 struct wined3d_context *context;
6179 IWineD3DSurfaceImpl *target;
6181 /* Recreate the primary swapchain's context */
6182 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6183 if (!swapchain->context)
6185 ERR("Failed to allocate memory for swapchain context array.\n");
6186 return E_OUTOFMEMORY;
6189 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6190 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6192 WARN("Failed to create context.\n");
6193 HeapFree(GetProcessHeap(), 0, swapchain->context);
6197 swapchain->context[0] = context;
6198 swapchain->num_contexts = 1;
6199 create_dummy_textures(This);
6200 context_release(context);
6202 hr = This->shader_backend->shader_alloc_private(iface);
6205 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6209 hr = This->frag_pipe->alloc_private(iface);
6212 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6213 This->shader_backend->shader_free_private(iface);
6217 hr = This->blitter->alloc_private(iface);
6220 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6221 This->frag_pipe->free_private(iface);
6222 This->shader_backend->shader_free_private(iface);
6229 context_acquire(This, NULL);
6230 destroy_dummy_textures(This, context->gl_info);
6231 context_release(context);
6232 context_destroy(This, context);
6233 HeapFree(GetProcessHeap(), 0, swapchain->context);
6234 swapchain->num_contexts = 0;
6238 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6239 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6240 IWineD3DSwapChainImpl *swapchain;
6242 BOOL DisplayModeChanged = FALSE;
6243 WINED3DDISPLAYMODE mode;
6244 TRACE("(%p)\n", This);
6246 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6248 ERR("Failed to get the first implicit swapchain\n");
6252 if(!is_display_mode_supported(This, pPresentationParameters)) {
6253 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6254 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6255 pPresentationParameters->BackBufferHeight);
6256 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6257 return WINED3DERR_INVALIDCALL;
6260 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6261 * on an existing gl context, so there's no real need for recreation.
6263 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6265 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6267 TRACE("New params:\n");
6268 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6269 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6270 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6271 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6272 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6273 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6274 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6275 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6276 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6277 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6278 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6279 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6280 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6282 /* No special treatment of these parameters. Just store them */
6283 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6284 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6285 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6286 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6288 /* What to do about these? */
6289 if(pPresentationParameters->BackBufferCount != 0 &&
6290 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6291 ERR("Cannot change the back buffer count yet\n");
6293 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6294 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6295 ERR("Cannot change the back buffer format yet\n");
6297 if(pPresentationParameters->hDeviceWindow != NULL &&
6298 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6299 ERR("Cannot change the device window yet\n");
6301 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6305 TRACE("Creating the depth stencil buffer\n");
6307 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6309 pPresentationParameters->BackBufferWidth,
6310 pPresentationParameters->BackBufferHeight,
6311 pPresentationParameters->AutoDepthStencilFormat,
6312 pPresentationParameters->MultiSampleType,
6313 pPresentationParameters->MultiSampleQuality,
6315 (IWineD3DSurface **)&This->auto_depth_stencil);
6318 ERR("Failed to create the depth stencil buffer\n");
6319 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6320 return WINED3DERR_INVALIDCALL;
6324 if (This->onscreen_depth_stencil)
6326 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6327 This->onscreen_depth_stencil = NULL;
6330 /* Reset the depth stencil */
6331 if (pPresentationParameters->EnableAutoDepthStencil)
6332 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6334 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6336 TRACE("Resetting stateblock\n");
6337 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6338 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6340 delete_opengl_contexts(iface, swapchain);
6342 if(pPresentationParameters->Windowed) {
6343 mode.Width = swapchain->orig_width;
6344 mode.Height = swapchain->orig_height;
6345 mode.RefreshRate = 0;
6346 mode.Format = swapchain->presentParms.BackBufferFormat;
6348 mode.Width = pPresentationParameters->BackBufferWidth;
6349 mode.Height = pPresentationParameters->BackBufferHeight;
6350 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6351 mode.Format = swapchain->presentParms.BackBufferFormat;
6354 /* Should Width == 800 && Height == 0 set 800x600? */
6355 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6356 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6357 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6361 if(!pPresentationParameters->Windowed) {
6362 DisplayModeChanged = TRUE;
6364 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6365 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6367 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6370 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6374 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6376 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6379 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6383 if (This->auto_depth_stencil)
6385 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6388 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6394 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6395 || DisplayModeChanged)
6397 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6399 if (!pPresentationParameters->Windowed)
6401 if(swapchain->presentParms.Windowed) {
6402 /* switch from windowed to fs */
6403 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6404 pPresentationParameters->BackBufferHeight);
6406 /* Fullscreen -> fullscreen mode change */
6407 MoveWindow(swapchain->device_window, 0, 0,
6408 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6412 else if (!swapchain->presentParms.Windowed)
6414 /* Fullscreen -> windowed switch */
6415 swapchain_restore_fullscreen_window(swapchain);
6417 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6418 } else if(!pPresentationParameters->Windowed) {
6419 DWORD style = This->style, exStyle = This->exStyle;
6420 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6421 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6422 * Reset to clear up their mess. Guild Wars also loses the device during that.
6426 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6427 pPresentationParameters->BackBufferHeight);
6428 This->style = style;
6429 This->exStyle = exStyle;
6432 /* Note: No parent needed for initial internal stateblock */
6433 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock);
6434 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6435 else TRACE("Created stateblock %p\n", This->stateBlock);
6436 This->updateStateBlock = This->stateBlock;
6437 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6439 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6441 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6444 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6447 GetClientRect(swapchain->win_handle, &client_rect);
6449 if(!swapchain->presentParms.BackBufferCount)
6451 TRACE("Single buffered rendering\n");
6452 swapchain->render_to_fbo = FALSE;
6454 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6455 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6457 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6458 swapchain->presentParms.BackBufferWidth,
6459 swapchain->presentParms.BackBufferHeight,
6460 client_rect.right, client_rect.bottom);
6461 swapchain->render_to_fbo = TRUE;
6465 TRACE("Rendering directly to GL_BACK\n");
6466 swapchain->render_to_fbo = FALSE;
6470 hr = create_primary_opengl_context(iface, swapchain);
6471 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6473 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6479 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6481 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6483 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6489 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6490 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6491 TRACE("(%p) : pParameters %p\n", This, pParameters);
6493 *pParameters = This->createParms;
6497 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6498 IWineD3DSwapChain *swapchain;
6500 TRACE("Relaying to swapchain\n");
6502 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6503 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6504 IWineD3DSwapChain_Release(swapchain);
6508 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6509 IWineD3DSwapChain *swapchain;
6511 TRACE("Relaying to swapchain\n");
6513 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6514 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6515 IWineD3DSwapChain_Release(swapchain);
6520 /** ********************************************************
6521 * Notification functions
6522 ** ********************************************************/
6523 /** This function must be called in the release of a resource when ref == 0,
6524 * the contents of resource must still be correct,
6525 * any handles to other resource held by the caller must be closed
6526 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6527 *****************************************************/
6528 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6530 TRACE("(%p) : Adding resource %p\n", This, resource);
6532 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6535 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6537 TRACE("(%p) : Removing resource %p\n", This, resource);
6539 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6542 void device_resource_released(IWineD3DDeviceImpl *device, IWineD3DResource *resource)
6544 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6547 TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
6549 context_resource_released(device, resource, type);
6553 case WINED3DRTYPE_SURFACE:
6554 if (!device->d3d_initialized) break;
6556 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
6558 if (device->render_targets[i] == (IWineD3DSurfaceImpl *)resource)
6560 ERR("Surface %p is still in use as render target %u.\n", resource, i);
6561 device->render_targets[i] = NULL;
6565 if (device->depth_stencil == (IWineD3DSurfaceImpl *)resource)
6567 ERR("Surface %p is still in use as depth/stencil buffer.\n", resource);
6568 device->depth_stencil = NULL;
6572 case WINED3DRTYPE_TEXTURE:
6573 case WINED3DRTYPE_CUBETEXTURE:
6574 case WINED3DRTYPE_VOLUMETEXTURE:
6575 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
6577 if (device->stateBlock && device->stateBlock->textures[i] == (IWineD3DBaseTexture *)resource)
6579 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6580 resource, device->stateBlock, i);
6581 device->stateBlock->textures[i] = NULL;
6584 if (device->updateStateBlock != device->stateBlock
6585 && device->updateStateBlock->textures[i] == (IWineD3DBaseTexture *)resource)
6587 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
6588 resource, device->updateStateBlock, i);
6589 device->updateStateBlock->textures[i] = NULL;
6594 case WINED3DRTYPE_BUFFER:
6595 for (i = 0; i < MAX_STREAMS; ++i)
6597 if (device->stateBlock && device->stateBlock->streamSource[i] == (IWineD3DBuffer *)resource)
6599 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6600 resource, device->stateBlock, i);
6601 device->stateBlock->streamSource[i] = NULL;
6604 if (device->updateStateBlock != device->stateBlock
6605 && device->updateStateBlock->streamSource[i] == (IWineD3DBuffer *)resource)
6607 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
6608 resource, device->updateStateBlock, i);
6609 device->updateStateBlock->streamSource[i] = NULL;
6614 if (device->stateBlock && device->stateBlock->pIndexData == (IWineD3DBuffer *)resource)
6616 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6617 resource, device->stateBlock);
6618 device->stateBlock->pIndexData = NULL;
6621 if (device->updateStateBlock != device->stateBlock
6622 && device->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource)
6624 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
6625 resource, device->updateStateBlock);
6626 device->updateStateBlock->pIndexData = NULL;
6634 /* Remove the resource from the resourceStore */
6635 device_resource_remove(device, resource);
6637 TRACE("Resource released.\n");
6640 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6641 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6642 IWineD3DResourceImpl *resource, *cursor;
6644 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6646 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6647 TRACE("enumerating resource %p\n", resource);
6648 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6649 ret = pCallback((IWineD3DResource *) resource, pData);
6650 if(ret == S_FALSE) {
6651 TRACE("Canceling enumeration\n");
6658 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6660 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6661 IWineD3DResourceImpl *resource;
6663 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6665 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6666 if (type == WINED3DRTYPE_SURFACE)
6668 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6670 TRACE("Found surface %p for dc %p.\n", resource, dc);
6671 *surface = (IWineD3DSurface *)resource;
6677 return WINED3DERR_INVALIDCALL;
6680 /**********************************************************
6681 * IWineD3DDevice VTbl follows
6682 **********************************************************/
6684 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6686 /*** IUnknown methods ***/
6687 IWineD3DDeviceImpl_QueryInterface,
6688 IWineD3DDeviceImpl_AddRef,
6689 IWineD3DDeviceImpl_Release,
6690 /*** IWineD3DDevice methods ***/
6691 IWineD3DDeviceImpl_GetParent,
6692 /*** Creation methods**/
6693 IWineD3DDeviceImpl_CreateBuffer,
6694 IWineD3DDeviceImpl_CreateVertexBuffer,
6695 IWineD3DDeviceImpl_CreateIndexBuffer,
6696 IWineD3DDeviceImpl_CreateStateBlock,
6697 IWineD3DDeviceImpl_CreateSurface,
6698 IWineD3DDeviceImpl_CreateRendertargetView,
6699 IWineD3DDeviceImpl_CreateTexture,
6700 IWineD3DDeviceImpl_CreateVolumeTexture,
6701 IWineD3DDeviceImpl_CreateVolume,
6702 IWineD3DDeviceImpl_CreateCubeTexture,
6703 IWineD3DDeviceImpl_CreateQuery,
6704 IWineD3DDeviceImpl_CreateSwapChain,
6705 IWineD3DDeviceImpl_CreateVertexDeclaration,
6706 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6707 IWineD3DDeviceImpl_CreateVertexShader,
6708 IWineD3DDeviceImpl_CreateGeometryShader,
6709 IWineD3DDeviceImpl_CreatePixelShader,
6710 IWineD3DDeviceImpl_CreatePalette,
6711 /*** Odd functions **/
6712 IWineD3DDeviceImpl_Init3D,
6713 IWineD3DDeviceImpl_InitGDI,
6714 IWineD3DDeviceImpl_Uninit3D,
6715 IWineD3DDeviceImpl_UninitGDI,
6716 IWineD3DDeviceImpl_SetMultithreaded,
6717 IWineD3DDeviceImpl_EvictManagedResources,
6718 IWineD3DDeviceImpl_GetAvailableTextureMem,
6719 IWineD3DDeviceImpl_GetBackBuffer,
6720 IWineD3DDeviceImpl_GetCreationParameters,
6721 IWineD3DDeviceImpl_GetDeviceCaps,
6722 IWineD3DDeviceImpl_GetDirect3D,
6723 IWineD3DDeviceImpl_GetDisplayMode,
6724 IWineD3DDeviceImpl_SetDisplayMode,
6725 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6726 IWineD3DDeviceImpl_GetRasterStatus,
6727 IWineD3DDeviceImpl_GetSwapChain,
6728 IWineD3DDeviceImpl_Reset,
6729 IWineD3DDeviceImpl_SetDialogBoxMode,
6730 IWineD3DDeviceImpl_SetCursorProperties,
6731 IWineD3DDeviceImpl_SetCursorPosition,
6732 IWineD3DDeviceImpl_ShowCursor,
6733 /*** Getters and setters **/
6734 IWineD3DDeviceImpl_SetClipPlane,
6735 IWineD3DDeviceImpl_GetClipPlane,
6736 IWineD3DDeviceImpl_SetClipStatus,
6737 IWineD3DDeviceImpl_GetClipStatus,
6738 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6739 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6740 IWineD3DDeviceImpl_SetDepthStencilSurface,
6741 IWineD3DDeviceImpl_GetDepthStencilSurface,
6742 IWineD3DDeviceImpl_SetGammaRamp,
6743 IWineD3DDeviceImpl_GetGammaRamp,
6744 IWineD3DDeviceImpl_SetIndexBuffer,
6745 IWineD3DDeviceImpl_GetIndexBuffer,
6746 IWineD3DDeviceImpl_SetBaseVertexIndex,
6747 IWineD3DDeviceImpl_GetBaseVertexIndex,
6748 IWineD3DDeviceImpl_SetLight,
6749 IWineD3DDeviceImpl_GetLight,
6750 IWineD3DDeviceImpl_SetLightEnable,
6751 IWineD3DDeviceImpl_GetLightEnable,
6752 IWineD3DDeviceImpl_SetMaterial,
6753 IWineD3DDeviceImpl_GetMaterial,
6754 IWineD3DDeviceImpl_SetNPatchMode,
6755 IWineD3DDeviceImpl_GetNPatchMode,
6756 IWineD3DDeviceImpl_SetPaletteEntries,
6757 IWineD3DDeviceImpl_GetPaletteEntries,
6758 IWineD3DDeviceImpl_SetPixelShader,
6759 IWineD3DDeviceImpl_GetPixelShader,
6760 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6761 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6762 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6763 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6764 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6765 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6766 IWineD3DDeviceImpl_SetRenderState,
6767 IWineD3DDeviceImpl_GetRenderState,
6768 IWineD3DDeviceImpl_SetRenderTarget,
6769 IWineD3DDeviceImpl_GetRenderTarget,
6770 IWineD3DDeviceImpl_SetFrontBackBuffers,
6771 IWineD3DDeviceImpl_SetSamplerState,
6772 IWineD3DDeviceImpl_GetSamplerState,
6773 IWineD3DDeviceImpl_SetScissorRect,
6774 IWineD3DDeviceImpl_GetScissorRect,
6775 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6776 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6777 IWineD3DDeviceImpl_SetStreamSource,
6778 IWineD3DDeviceImpl_GetStreamSource,
6779 IWineD3DDeviceImpl_SetStreamSourceFreq,
6780 IWineD3DDeviceImpl_GetStreamSourceFreq,
6781 IWineD3DDeviceImpl_SetTexture,
6782 IWineD3DDeviceImpl_GetTexture,
6783 IWineD3DDeviceImpl_SetTextureStageState,
6784 IWineD3DDeviceImpl_GetTextureStageState,
6785 IWineD3DDeviceImpl_SetTransform,
6786 IWineD3DDeviceImpl_GetTransform,
6787 IWineD3DDeviceImpl_SetVertexDeclaration,
6788 IWineD3DDeviceImpl_GetVertexDeclaration,
6789 IWineD3DDeviceImpl_SetVertexShader,
6790 IWineD3DDeviceImpl_GetVertexShader,
6791 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6792 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6793 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6794 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6795 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6796 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6797 IWineD3DDeviceImpl_SetViewport,
6798 IWineD3DDeviceImpl_GetViewport,
6799 IWineD3DDeviceImpl_MultiplyTransform,
6800 IWineD3DDeviceImpl_ValidateDevice,
6801 IWineD3DDeviceImpl_ProcessVertices,
6802 /*** State block ***/
6803 IWineD3DDeviceImpl_BeginStateBlock,
6804 IWineD3DDeviceImpl_EndStateBlock,
6805 /*** Scene management ***/
6806 IWineD3DDeviceImpl_BeginScene,
6807 IWineD3DDeviceImpl_EndScene,
6808 IWineD3DDeviceImpl_Present,
6809 IWineD3DDeviceImpl_Clear,
6810 IWineD3DDeviceImpl_ClearRendertargetView,
6812 IWineD3DDeviceImpl_SetPrimitiveType,
6813 IWineD3DDeviceImpl_GetPrimitiveType,
6814 IWineD3DDeviceImpl_DrawPrimitive,
6815 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6816 IWineD3DDeviceImpl_DrawPrimitiveUP,
6817 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6818 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6819 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6820 IWineD3DDeviceImpl_DrawRectPatch,
6821 IWineD3DDeviceImpl_DrawTriPatch,
6822 IWineD3DDeviceImpl_DeletePatch,
6823 IWineD3DDeviceImpl_ColorFill,
6824 IWineD3DDeviceImpl_UpdateTexture,
6825 IWineD3DDeviceImpl_UpdateSurface,
6826 IWineD3DDeviceImpl_GetFrontBufferData,
6827 /*** object tracking ***/
6828 IWineD3DDeviceImpl_EnumResources,
6829 IWineD3DDeviceImpl_GetSurfaceFromDC,
6830 IWineD3DDeviceImpl_AcquireFocusWindow,
6831 IWineD3DDeviceImpl_ReleaseFocusWindow,
6834 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6835 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6836 IUnknown *parent, IWineD3DDeviceParent *device_parent)
6838 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6839 const struct fragment_pipeline *fragment_pipeline;
6840 struct shader_caps shader_caps;
6841 struct fragment_caps ffp_caps;
6842 WINED3DDISPLAYMODE mode;
6846 device->lpVtbl = &IWineD3DDevice_Vtbl;
6848 device->wined3d = (IWineD3D *)wined3d;
6849 IWineD3D_AddRef(device->wined3d);
6850 device->adapter = wined3d->adapter_count ? adapter : NULL;
6851 device->parent = parent;
6852 device->device_parent = device_parent;
6853 list_init(&device->resources);
6854 list_init(&device->shaders);
6856 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6857 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
6859 /* Get the initial screen setup for ddraw. */
6860 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
6863 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
6864 IWineD3D_Release(device->wined3d);
6867 device->ddraw_width = mode.Width;
6868 device->ddraw_height = mode.Height;
6869 device->ddraw_format = mode.Format;
6871 /* Save the creation parameters. */
6872 device->createParms.AdapterOrdinal = adapter_idx;
6873 device->createParms.DeviceType = device_type;
6874 device->createParms.hFocusWindow = focus_window;
6875 device->createParms.BehaviorFlags = flags;
6877 device->devType = device_type;
6878 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
6880 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
6881 device->shader_backend = adapter->shader_backend;
6883 if (device->shader_backend)
6885 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
6886 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
6887 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
6888 device->vs_clipping = shader_caps.VSClipping;
6890 fragment_pipeline = adapter->fragment_pipe;
6891 device->frag_pipe = fragment_pipeline;
6892 if (fragment_pipeline)
6894 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
6895 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
6897 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
6898 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
6901 ERR("Failed to compile state table, hr %#x.\n", hr);
6902 IWineD3D_Release(device->wined3d);
6906 device->blitter = adapter->blitter;
6912 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6913 DWORD rep = This->StateTable[state].representative;
6914 struct wined3d_context *context;
6919 for(i = 0; i < This->numContexts; i++) {
6920 context = This->contexts[i];
6921 if(isStateDirty(context, rep)) continue;
6923 context->dirtyArray[context->numDirtyEntries++] = rep;
6924 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
6925 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
6926 context->isStateDirty[idx] |= (1 << shift);
6930 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
6932 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
6933 *width = context->current_rt->pow2Width;
6934 *height = context->current_rt->pow2Height;
6937 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
6939 IWineD3DSwapChainImpl *swapchain = context->swapchain;
6940 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
6941 * current context's drawable, which is the size of the back buffer of the swapchain
6942 * the active context belongs to. */
6943 *width = swapchain->presentParms.BackBufferWidth;
6944 *height = swapchain->presentParms.BackBufferHeight;
6947 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
6948 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
6950 if (device->filter_messages)
6952 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
6953 window, message, wparam, lparam);
6954 return DefWindowProcW(window, message, wparam, lparam);
6957 if (message == WM_DESTROY)
6959 TRACE("unregister window %p.\n", window);
6960 wined3d_unregister_window(window);
6962 if (device->focus_window == window) device->focus_window = NULL;
6963 else ERR("Window %p is not the focus window for device %p.\n", window, device);
6966 return CallWindowProcW(proc, window, message, wparam, lparam);